9 ms·
With gnu make you don't even need OBJs for a simple directory in which all the .c files are compiled: .SECONDEXPANSION foo: $$(patsubst %.c,%.o,$$(wil
by gumby 3y ago
With gnu make you don't even need OBJs for a simple directory in which all the .c files are compiled:
.SECONDEXPANSION
foo: $$(patsubst %.c,%.o,$$(wildcard *.c))
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
Admittedly you can end up with short, very general Makefiles that look like they were a Prolog program written in TECO. But the advantage is that they are general so don't need to be fiddled with as your project grows.
I make small Makefiles like this that ensure my local build environment is correct for the package, then call cmake.
- JadeNB 3y ago> a Prolog program written in TECO I know we don't do general-purpose "I like this" comments on HN, but, as a Christmas treat to myself, I'm just going to say how happy this little sentence fragment makes me.
- gumby 3y agoThanks! I aim to please. As it happens I used to program in both Prolog and TECO, in the same period of time but of course not on the same code bases.
- bigdict 3y agoJust do: .SECONDEXPANSION foo: $$(patsubst %.c,%.o,$$(wildcard *.c)) No need to tell Make how to invoke a C compiler for the billionth time.
- rurban 3y agoBut then you need the name it GNUmakefile when you use incompatible GNU extensions. BSD makefiles do look better.
- Brian_K_White 3y agoGlobbing is possible but unwise. You do want a variable with an explicit list of sources, even while trying to make things as automatic and dynamic as possible.
- adrian_b 3y agoWhy would you want that? In decades of programming in very varied environments I have never compiled any software project otherwise than by using globbing, so that I have never needed to waste time to write the name of any source file in a Makefile. I have never seen any reason to do otherwise. For instance, using special compilation flags for a certain source file, different from the others, is something that I consider a mistake. Whichever is the goal, it certainly can be achieved by other means (e.g. pragmas or attributes). Moreover, the dependencies for any file must always be generated automatically, they must never be written explicitly, which removes the main reason why in bad Makefiles the names of the source files are written individually.
- dataangel 3y agoglobs don't even prevent you from special casing one file to have different flags
- adrian_b 3y agoTrue, but this should better be avoided, because in such cases reading the source files is not enough to understand what they do. You must also be aware that they are compiled in a different way and you must search a frequently too big and obfuscated Makefile to discover which is the applicable compilation rule. Unfortunately I have seen many projects that had used such tricks and it was always painful for maintenance to discover how they were supposed to work.
- an_d_rew 3y agoGlobbing means that the directory has to be scanned on every build Once you start getting to multiple directories and recursive scans, the build time begins to grow enormously and usually unexpectedly. Not a problem at all for small or even medium size projects on a fast machine. But once you start building very large projects with multiple sub-projects, it generally slows the machine to a crawl on every build.
- 3y ago
- adrian_b 3y agoUsing these and other similar features of GNU make it is possible to write a generic Makefile that works for any software project. It appears that almost nobody reads the manual of GNU make, despite the fact that it is extremely instructive. I have read the GNU make manual once, about 25 years ago. Then I have written a set of small Makefiles that I have used in all my software projects forever, until now, with only extremely small changes during the years, e.g. when new compiler options have appeared, or when I have added compilers for additional CPU targets or operating system targets or additional programming languages. It is possible to make such generic Makefiles that will work in any software project. For example, in the simplest case, when the source files are in a single directory and you use that directory also for building the project, copying a small template Makefile that includes the appropriate generic Makefile for the target CPU and operating system is enough so that "make" will identify all the kinds of source files that exist in the directory, generate the necessary dependence rules, invoke the appropriate compilers and build the executable. For any more complex project, only a minimum of information needs to be added to the template Makefile. For instance, when the build is done in another directory than the one with sources, or when there are multiple directories with source files, a list of directories with source files must be added into the template Makefile. Lists of non-standard libraries, non-standard library directories and non-standard include directories may be added. Additional options can be specified, e.g. building a shared library, not an executable file. Besides these, nothing specific to the project needs to be written. Adding or deleting source files or renaming source files do not need any changes in the Makefile, but after such changes a "make clean" is recommended. Instead of this simple and obvious approach, more than 99% of the software projects that I have seen use absolutely horrible huge and unmaintainable Makefiles, or they use "make" replacements like "cmake", which are much worse than the traditional "make", so I fail to understand why anyone would want to use them.
- dagmx 3y agoI think you’re overstating the ease of use of make. How does one discover dependencies in a cross platform way with Make without writing the logic themselves to stay up to date with platform changes? Or picking up configuration options from dependencies. How does one make use of Ninja with make? Or discover changes to sdk paths for new platforms? You end up having to duplicate that logic across every repo that needs it. Along the way you accrue lots of variance. In the end you get something that is difficult to debug and scale. That’s why so many projects moved to cmake. It scales better. In much the same way that you can technically do anything you need with C, but other languages add ergonomics and scalability that people value more.
- lhamil64 3y agoI admittedly don't have a ton of experience with make, but what's the point of doing this vs just throwing the compile commands in a shell script?
- dpkirchner 3y agoThe biggest practical difference is that make can test to see if a file needs to be rebuilt before proceeding.
- adrian_b 3y agoYes, exactly this. When compiling a project once from a clean state make has no advantage over a shell script that would use a tool like "parallel" to distribute compilation jobs over all available CPU cores. However writing such a script for parallel compilation is more complex than writing a simple Makefile executed with "make -j N". As you say, the main reason of existence of "make" is the acceleration of the recompilation of a project after incremental changes in the source files, when only the files that depend on the changes are recompiled, saving time.
- f1shy 3y agoMake will automatically do all the steps, and stop if any one fails. Of course you van do manually, but is much more work.
- dagmx 3y agoThe irony is that the same argument would work against Make in the description further up vs other build systems like CMake etc. Not to take away from your correct answer of course
- gumby 3y agoThat’s because CMake calls make or an equivalent (ninja, xcodebuild…) that actually does all the dependency checking!
- 3y ago