C Programming: Makefiles

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi good evening today we're going to talk about automating your builds with make files this is intended primarily for people who are doing programming in C or C++ typically on like a Linux environment a command line environment what I wanted to do it will show you how to take a basic C file or C++ file and compile it and then show you how you can automate that build using something called a make file so that all you have to do is type in one single command and it will build your entire project from scratch every time you do that so what I have here on the screen here is just a simple little program it contains a main down here at the bottom and what this program does is it just basically computes the distance from the origin to some X Y value on the coordinate system so it prompts you to enter an x and a y value and then it computes the distance using the distance formula then prints it out some silly little program but what I've written here is a function called get double and what get double does is it has given a prompt and then a minimum value and a maximum value and it prints out the prompt prompts the user to type in a double value and then make sure that value is within the the specified range and if it's not then it goes back and Reap romps the user over and over again so a nice little like utility function that you might want to use in your program okay so let's compile this so go clang GMC OGM and right now it comes back and it gives us an error and it says there's an undefined reference to POW and square root those are the functions invoked here and here those are functions that I didn't supply they're actually part of the math library so to get this to compile correctly I need to run that command again but add on dash L and M like this and that tells it to link to the math library there's actually a file out there called Lib m-dot some extension usually so or so2 does as it goes out it looks for that file lib m dot s o in this case shared object and it links that into your program you may be wondering like why isn't this sufficient to include the square root and power power function that's because the math dot H file does not actually contain the code for doing the square root and doing the exponent or the power function it just contains the function prototypes and I'm going to show you during this live stream about function prototypes and why they go into these files called dot H but the important thing is that math dot H does not contain the actual code for doing square root and power all it does is includes enough information so the compiler knows about the existence of the functions but doesn't actually have the code for it itself you need to link it in with the math library to get the actual code for the square root and the power functions among among all the others that are part of the math library okay so this compiles the program and then I can run it and it says enter the x value so I could do like three by is four and I get five as the distance and so we know it's working correctly okay so I want to before we go much further I want to talk to you about the what happens when you actually invoke the C compiler ours is called clang you may be using GCC there's a bunch of others but all the options are pretty much the same so we start with a source file like a dot C file and then that goes through what's called the preprocessor and the purpose of the preprocessor is to handle things like the hash include' and the hash define directives and it also strips out comments okay so the preprocessor does two things it handles all the directives that start with that the hashtag in front of them and it also strips out any comments entering your programs if there's a bunch of other things that it does but those are the two primary things that it does and then what you get out of this preprocessor is a processed C file that has literally if I switch back to the screen here it's taken the contents of these files here went out on disk found that found those files and it just copied and pasted them right into your program so actually your program gets huge at this point because these two files standard IO dot H and math dot H are fairly big and they just get copied and pasted right into that right of that spot right there okay so I don't know what this this is a processed file of some sort but at this point it now goes through the actual compiler and the purpose here is to translate C to assembly okay so the compiler actually doesn't produce an executable the compiler just converts the source file into an assembly file and so what you get out is a file that ends in dot dot s okay and there it goes through the assembler and the purpose here is to translate assembly to what's called an object file so this object file has nothing to do with objects like in C++ or Java it's called an object file because it's a compiled file that has been targeted for a specific CPU and a specific operating system but it's not a Khaleed executable so the extensions on these object files are dot o little o and then from there it goes through something called the linker and this brings together object files and produces an executable okay so your C file starts as a Rossi file it goes through the preprocessor then it goes through the compiler the assembler the linker and then finally you get an executable down when all of this is done incidentally each one of these steps can be invoked with a specific option to the compiler and again it doesn't matter whether you use clang or GCC it's the same options for both to run the preprocessor it's - capital e to run the compiler and stop at the source file it's excuse me at the assembly file it's - capital S and then to run the process all the way through to the object file it's - and then a little C and then the linker is actually invoked as the last step and there's a way to invoke just the linker but it's not important at this point what that is these these three options here AES and C or the the option of the important ones for now okay so just to recap here if you do clang or GCC - capital e it will start with your C file pre process it and then stop and then if you do clang or GCC - s it'll start with your C file compile it down to assembly and then stop and then if you do the same thing with - C it starts with a C file it goes all the way down to the object file and stops and then if you just invoke it with no options whatsoever it goes all the way through the whole process okay so let's switch back over here oh let me let's do this let's go new screen so what I've got here is I have a file called GMC right and what I could actually do let's see oh yeah and what I'm doing right now is I'm just running clang GRC - OH GM and then I get an output called GM right so that's this one one command that takes the C file brings it through all the processes all the steps and then outputs and executable okay but now what I'm thinking is with my program here this get double function you know might be kind of Handy to to use and other programs like that you know this is actually a fairly handy little utility program so I happen to have another one here called tip and for those of you in the United States it's fairly common at the end of a meal and a restaurant to get your bill at the end and then you see the amount and then you leave what's called a tip for the waiter the waitstaff and then that's the total amount that you pay and so you decide what the amount of tip that you want to pay is typically it's about 10 or 15% maybe a little bit more but usually that you add that on to the bill so that's what this program does is you enter the price of a meal you enter the tip amount it calculates the amount of your tip calculates the total amount and then prints it out okay so let's try it out so enter the price of the meal let's say it's $20 and I want to relieve a 15% tip so it says that I should leave a $3 tip and the total amount is $23 okay but like I said this this get double would be a handy function to run here because you know I want to be able to make sure that they type in a say a positive number for the price of the meal and a tip amount should also be a positive number and should be between like zero and 100 hundred percent whereas the price of eel could be zero to just about anything so to be able to use get double here of course the kind of naive way to do it is let's take that and we'll come it paste it over here so there it is and then here I can say price equals get double and the hoop the meal should be between zero and let's say thousand dollars and then for the tip that should be between zero and a hundred percent okay so let's save it recompile it there we go and then we'll run it so let's say twenty dollars and then for the tip amount we you know accidentally put in 150 so it says tip amount must be at most one hundred we can put in a negative number and it says it has to be at least zero so we can put in 15 and then so it's working here okay so the point of this was I have this function called get double and in order to use it in two different programs I had to copy and paste it into both the files and of course you're thinking it's gotta be a better way to do this what I want to be able to do is take get double out of this file and put it into its own file and then have it have both of those programs refer directly to it so that's what we're going to do is I'm going to copy this and then I'm going to create a new file paste it in and then we'll save this and we'll call this something like GDC get-get CC and then in my geometry program I can get rid of it I don't need it because it's in another program note another file same thing in tip I can get rid of it there okay so save save and save and now what I want to do is compile all three of these files separately so that I can then link them all together at the very end if you remember that picture we had we're going to compile them what we're going to do is we're going to compile them and we're going to go as far down that that diagram as getting to the object files so we'll have an object file for each of the three geometry okay so let's let's try this out so down here I'm going to go G clang dash C because I only want to go as far as creating an object file GDC and this one gives me some warnings it says I don't know what printf and scanf are and that's because in my GDC file I need to include standard IOH so that GDC knows about these functions so I've saved it let's try it again okay wait hey dot compiled and it looks like in the directory I now have a file called GD 0 that contains the compiled version of GDC it's not a complete executable I can't run it but it's it's the compiled version of GDC and now let's try to do the same thing for geometry dot C and it says can't do that or at least it gives you a warning it says you're trying to use a function called get double and I don't know what get double is so the the solution here well one thing we could do is we could say include GDC like this and you remember what I said about how the preprocessor goes out and it finds that file and it copies and pastes the Const of the file right into your program so it will go out and find GDC the current directory that's what the double quotes mean the double quotes means look in the current directory for GDC and when it finds it it'll open it up and copy and paste the contents right to that spot so it's just like we wrote the get double function right there in the program but you'll find that if we do this then it it compiles just fine actually we can make a complete executable out of it and link to the math library okay so it works just line three for distances five okay but what what we haven't done is we haven't really compiled the two files separately what we did was we took GMC and then copied and pasted GDC right into it and then compiled that one file so imagine if we had a really really large project here where it might be thousands of C files perhaps a million or so lines of code what we don't want to be doing is taking all of our C files and copying and pasting them into one giant file because that would mean we'd have to compile a 1 million the result of the copy/paste would be a 1 million line file that we would have to compile all at once what we want to do is compile each one of the files separately so that if we change one of the files we can just recompile that one small one and then link them all back together again ok this is a lot lot faster than compiling a million lines all at once so just change one little file recompile it link it all together and then you got a new executable so what I really want to be able to do is compile GMC separately totally independently from GDC rather than including them but you saw how if we take out this include it doesn't doesn't work so well so that's because Giambi needs to know about the existence of get double doesn't need the code for it just needs the though the existence which means all it really needs is a function prototype for it character pointer prompt double min and a little max okay there's the function prototype forget double and if we save that we can see that we can compile GMC as a to an object file so now I have where is it let's try that again oh yeah here it is Giotto right there I didn't see that at first but there is the object file here's gd0 there's this object file and then we can just we can just compile the link the two of them together so if we say clang GMO and gd0 and output that as geometry geometry of a math library then we get a complete executable and then we can run it three four outputs five okay so let's switch back to this picture here and let's start a new diagram so I have GMC and GDC and I want to compile this with clang dash C Giambi C and the output of that will be G m dot o and then with GDC I'll compile that one with clang dash C GDC and the output of that is GD dot zero and then I will linked them together with playing GMO GD do and then output it to GM and then don't forget to link in the math library so there's the one the one big command that I use there and then the output of that is the executable so it's three commands to compile this program but those are all the steps separately done and and it seems like it's complicated now but it's actually going to save time later on ok now let's think about what we want to do with our other file which was tipsy right so I wanted to compile that and make tiptoe and I would use a command that's very similar to this one but it would just be a tip dot see right here and then I would link GTO and tip dot o directly together to make my tip program and the command I would use there is clang tip dot o GD 0 - Oh tip and this one doesn't need the math library doesn't need the sine the cosine so I don't have to link in the math library but that's the command I would use to bring those together now here's where the payoff is is that I only had to compile GD 0 once and then I'm able to use it in two different programs over here ok so let's try that out on this screen let's go back to my tip program here and I'll include the function prototype double get double character pointer prompt double min little max I'll save it so I can compile tipsy and then I was linked it all together tiptoe gd0 - Oh tip and it compiles and then I can run it $20 15% tip $23 total okay so so what I did there was just to recap compiled GMC into GM 0 same thing with GDC and tipsy and then I linked both of those together to make this executable and I linked GTO and tiptoe together to make this executable okay so if you had to do this that well let's see what I want to go just two things I want to do so I want to actually kind of go back to this program here and and the last thing I want to show you is that it's kind of a pain here to have to type in the function prototype for get double twice what I want to be able to do is have both the programs be able to know what the function prototype forget double is and you do that by making what's called a header file this is exactly what I typed in before but I've just put it into its own file so I'm going to save this as geh so H files are just C or C++ files they're they're actually no different the extension is the only thing that's different on them the implication of making it an H file header file is that it doesn't contain any actual C code it only contains things like function prototypes global variable definitions defines includes and things like that but no actual code itself and then in tipsy I can just say include GTH and in Giambi I can do the same thing and then let's just verify that it all compiles okay there's tipsy and there's Giambi they compiled just fine and then I can bring tiptoe and gd0 together to make the tip program do the same thing for the geometry program and then that one compiles together all right so now you understand hopefully why math dot H and standard IO dot H don't include the actual code for printf scanf square root sine cosine they only contain things like function prototypes and the actual code needs to be somewhere else and some other file that gets linked to it at the very end when we compile when we link with the - LM module LM option it's saying go out and find at a pre compiled object file they're already they're out there on the computer's disk and then lengthen together at the very end so instead of having to supply the name of the dot o file you just say - LM and it goes out and finds the file and it links it in for you okay so so that's the general process here so what we're going to do now is show you how to automate this picture this picture here and something called a make file so that will do all those commands for us automatically ok so that's the next thing we're going to do so let's create a new file and this file should be called make file and actually by convention it's given a capital M but it doesn't matter really but the convention is it's given a capital M with its name oops I just over out some other make file let's try that again there we go so the first line of your make file should be this this is this is actually a comment starts with a hash mark character it's that indicates that it's a comment what this comment does is it tells this editor to format this file as a make file in particular the formatting for a make file is very specific it's broken up into a bunch of chunks and each one of these chunks is called a recipe and the recipes have the format target colon dependencies and then on the next line there's a tab and then an action that you take and this is the important part here is this right here has to be a tab in other words you're going to hit the tab key on your keyboard and most of the time what the editor is going to do is instead of actually inserting one single ASCII tab character which i think is a control I it's going to put in four spaces and that's actually not allowed in a make file it has to be one single tab character so putting in this comment at the top tells the editor disable the the action to disable the default of putting in four spaces and actually allow me to put in a single tab okay so this diagram that we have is called a dependency tree okay it says that in order to build this executable it depends upon GM 0 and GTO existing and in order to build giotto it depends upon GMC in order to build gto depends on GDC same thing for tiptoe and tipsy so there's a dependency here that GM depends on these - and then Giotto depends upon this one and gto depends on this one so we're going to embed this entire diagram in that make file so this is the format of it yeah actually I want to turn these in the comments so they don't get acted on okay so the first target is going to be Jian and it depends upon GM 0 and gto and then for the action we're going to put down what command you would type in on the command line to build GM these two files and from our diagram it's it's this command so we're going to put that in clang GM o GD 0 - oh gee um - LM ok and then we've got to write 2 more recipes because there's a dependency here so GM 0 depends upon GMC and the command to build GM 0 from GMC is clang - e FC GMC and then one last recipe Gd dot o depends on paw and GDC and the command to build it is clang - see GDC so let's save that and now what I'm going to do is I'm going to remove all the files that I don't need so remove the O files and Jia mand tip ok so that leaves just the the C files and the H files and if I just type make it runs all three commands that are needed to build the geologists did them all so it basically did this command this command and this command and what it did was it started at the top and it said okay I need to build Jeon I need to build it out of these two files but I don't see those here so I need to build it I need to build this file out of this one oh I do see this one here so I'm going to run this command to build this file and then it comes back down this branch of the tree and it goes out I don't see GTO here but I do see GGC so I'm going to run this command and then to build this file and now that I have both of these files I can run this command to build this one okay so it walks down the tree and then walks back up the tree to build things and we can see that in the order of the commands that I ran it did Giambi first or when down the left side of the tree then it did GDC so it went down the middle of the tree and then once it had both of those object files it can then run the command at the top of the tree okay let's do the same thing now for the other side the tip side so we'll go tip is built out of tiptoe and gd0 and the command to run that to build that is clang tip 0g amo sorry GED zero and output to tip okay and then I need one more recipe in here and that's to build tip zero out of tipsy and then we'll save it and if I type make it's actually going to say GM is up to date it in or didn't build tip and the reason for that is the make file or the make program starts at the top of this file and it just executing instructions for the first recipe that defines so it found this one it built this this target and then it stopped so I need to so in order to make it build this one I just come to the command line and say make tip the name of the target that I want and it goes down and jumps to that target and then builds that target from those dependencies okay so it's a bill geom I just type make and it does that because that's the first one and to build tip I just I say make tip and it builds that one okay and then let's go let's remove everything again so we'll go remove start out Oh tip and Gian okay and then what I'm going to do here is I'm going to this is actually what's typically done is if you want to build multiple targets in this case you have to add another rule another recipe that's and usually that recipe is called all and you just list out after after the after the word all each of the targets that you want to build by default that's all you got to do there and there's no action you write for that no action at all so what it does is it starts at the top it finds this target and says oh I need to build this one and this one and then it goes and it builds this one and it builds this one and then you're done so we'll save that and now I can just type make or I can type make all same thing just type make and it very quickly goes and it builds everything that's really cool so now I could do something like let's say I go into here and I and I change something here like let's change this to miles okay I know the units don't matter but I just made one little change I saved it and now I'm just going to type make and notice that it only recompiles the one file that changed and then re links everything together okay that's this is the real awesome thing about make files is that only it actually looks in the dependency tree so it looks down this tree and it goes okay I need to build GM I see GM 0 here but it is older than GMC so I'm going to recompile it and then G do but that's newer than GDC so I don't need to recompile so it doesn't rebuild this but then since this dependency changed it reruns this command and builds this one and then it walks down this tree and it goes didn't change didn't change nothing to do and then it stops there alright so we've we've embodied the entire dependency tree in this thing called the make file and we wrote very simple rules we put in a target we put in what it depends upon and then we put in a rule to describe how to build that now actually our our make file isn't quite complete because there's one file that's in our project it isn't listed in this make file and that's this one this GTH ok so what we actually need to do is say GMO depends not only on GMC but also on GD dot H because if we were to ever change this header file like add on a new a new function to it or if we were to let's say change the function prototype change the name of the function or change one of the types then we would want to recompile the geometry file and the same thing for tip okay that header file ever changes we want to recompile and probably the same thing for G zero although it's not listed explicitly in the header file basically what you do is you go through your your C file and you look for anything that's included so anything that's anything is needed to build this particular file you need to include in the the make file now we don't have to include standard IOH because that like for all intensive purposes never changes so you'd have to worry about that but Chicka dot H might might change so we need to list that here in our make file and what that means is that our picture actually changes a little bit here we have a new thing called GD H right here and there's a dependency here on that to go to that one and there's a dependency to go to that one there okay so so if this file ever changes we want to make sure we recompile this one to build this one and this file ever changes we'll rebuild this one in fact well let's demonstrate that so let's go into G Delta H and let's do something let's make a change to it but let's like we can even just add a comment okay that's enough to make this file change and then we'll go down here we go make and though I didn't save my make file there we go make and then it rebuilds the whole thing okay but notice that GGC is not included here because it didn't change the only thing that change was gdh alright so so that's the basic idea behind make files is it embodies a dependency tree and the function for the the format for it is really simple it's a target dependencies and then an action to take and usually the action is to build build the target out of these dependencies and then you put in the whole thing there's tons of shortcuts that you can put into this and you can actually honestly you can write one rule that does the whole thing basically that says you write one rule it basically does pattern matching this is anytime you see a dot C file run this command on it but I won't get that into that here you can look those up the last thing I want to do is I want to put in a couple of additional rules here's a new here's one that's usually put in it's called clean this one doesn't have any dependencies it's just a target but it does have an action so the purpose of this one is to clean up your project directory so you leave just the source files it removes the object files and removes the executables okay I'll save that and if I say make clean then it cleans up my directory and then I can say make and then it rebuilds the whole thing so if you ever want to just kind of start over again if you want to clean up your entire project and rebuild it from scratch you go make clean and then make and then it's to commands to do it all okay but you don't really have to do make clean every single time you know I've seen people kind of get in the habit of always doing a make clean and then a make everything would say they change one file and then do a make clean and then you do a make and for small projects not a big deal if it was a big project with a couple hundred or a thousand files in it you really don't want to be doing it make clean every time you change one little file okay so you can put recipes in the make file that have a target but no dependencies and you can put in recipes that have a target and only dependencies or we can mix and match the last thing I want to do is show you what happens if you put in a rule here but instead of typing a tab you put spaces in okay I'll save that I'll go make clean and you get this error message it says missing separator and that error message should it doesn't really describe what's going on but it should just tell you that it encountered a space here and instead of a tab okay so I've just deleted those spaces on a hit tab and then if I do make clean now then it works so last thing you know probably better to put a dash F here that way if see if I do a make clean Oh see if I take off the dash F I'll show you what happens make clean then you get this error message it says can't remove dot Oh can't remove tip and Giambi's so you just get error messages out of that and so I put on the dash F to say force the removal but don't complain if they don't exist alright so that's a little bit better and tell you a personal story here it's it's it's nice to have make files where you've typed in this command and you vetted and you make sure it works there was one time I was working on a project this was late at night with pulling an all-nighter and in my in my 3:00 a.m. stupor of not being able to think straight I wanted to delete all the files in my project at least clean it up so I could read we compile it from scratch and I didn't know about make files at this time so I type this accidentally put a space between the star and the dot oh and then what happens is the remove command silently removes everything and then says can't find a file called dot oh and that's when I started to sweat profusely because I realize what happened here is it has just deleted all of my files and so from that point forward in my career I've always made sure that whenever I remove things with the wild-card there I look at it like two or three times and make sure I didn't accidentally put a space in there or I make a make file and put that command in there and I make sure that it works and then I never type the remove plan myself I just type make clean and I know that it's going to work so another purpose of make files is to eliminate errors like that all right so that's pretty much what I had for you as far as make files I see there's a couple people watching on on on the live stream that's great if you've got any questions now would be the time to post it otherwise I think what I'll do is I'll call it good for now and I'll see you guys next time all right bye bye
Info
Channel: Barry Brown
Views: 158,917
Rating: 4.9665236 out of 5
Keywords: makefile
Id: GExnnTaBELk
Channel Id: undefined
Length: 44min 21sec (2661 seconds)
Published: Sun Apr 03 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.