Search code examples
makefilegdal

Cannot pass flags to Makefile to compile my code


I have a project that basically compiles from the command line in the following form: g++ -o stack_raster stack_raster.cpp -lgdal -lboost_filesystem -lboost_system

I made a Makefile, and this is the content:

CXX =g++ 
LDDFLAGS = -lgdal -lboost_system -lboost_filesystem
all: clean stack_raster 
clean: 
    rm -f stack_raster 

However I got a collect2: error: ld returned 1 exit status. A second variation of my Makefile I tried was:

CXX = g++ 
CPPFLAGS = -lgdal -lboost_system -lboost_filesystem 
all: clean stack_raster 
clean:
    rem -f stack_raster 

but I still receive the following message (even though the compile flags appear as they should for my program to compile successfully).

collect2: error: ld returned 1 exit status
<builtin>: recipe for target `stack_raster` failed 
make: *** [stack_raster] Error 1

Does anyone could help me with a reference or hint about my problem, and how could I tackle it?


Solution

  • Does anyone could help me with a reference or hint about my problem, and how could I tackle it?

    To begin with, you should have a look at the actual link command that make executed. It should have been echoed to make's output just before the error message from collect2. Understanding what's wrong with the command is the first step in determining how to fix your makefile.

    In the first case, the command is probably something like

    g++ stack_raster.cpp -o stack_raster
    

    In the second, it is probably something like

    g++ -lgdal -lboost_system -lboost_filesystem stack_raster.cpp -o stack_raster
    

    The latter is probably also very similar to what you would get with the first makefile if you corrected the spelling of LDDFLAGS to LDFLAGS.

    You will note that the library flags come in a different place in that command than they do in your manual command, and I assume you know that the order of objects and library flags on the linker command line is significant to Unix-style linkers such as GNU's (which is the one that the g++ driver will use).

    You can certainly fix this by writing an explicit rule, as you describe in your own answer, but your makes' built-in rules may be up to the task, too. If you are using GNU make then they certainly are. For this purpose it is useful to know what the built-in rules actually are, and essential to know what the variables on which these rules depend mean.

    Specifically,

    • LDFLAGS provides options to pass when invoking the linker, and conventionally, they appear on the command line before the objects being linked. As a result, this variable typically is not appropriate for specifying libraries (but it is fine for other link-specific options, such as -L to add directories to the library search path).

    • CPPFLAGS provides options for modulating the behavior of the C preprocessor (including when compiling C++). These do not typically appear at all in link(-only) commands executed by make, but they will appear (early) in commands for compiling object files from C or C++ sources, and in rules for building executables directly from C or C++ sources.

    Neither of those is what you want, but if you are using GNU make, then its documentation for the former explicitly tells you what (with that make implementation) you should do instead:

    Extra flags to give to compilers when they are supposed to invoke the linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable instead.

    (emphasis added)

    In GNU make, and perhaps some others, the LDLIBS variable serves exactly the purpose you need: to specify the libraries to link. These will appear at the end of the link command line from built-in rules, as you can confirm from GNU make's catalog of implicit rules, or from the list obtainable by running make -p in a directory containing no makefile.

    So, with GNU make you can get the build you seem to want from the built-in rules, with this:

    CXX = g++ 
    LDLIBS = -lgdal -lboost_system -lboost_filesystem
    
    all: clean stack_raster 
    
    clean: 
        rm -f stack_raster 
    

    In closing, I note that cleaning before building by default, as your examples do and mine imitates, largely defeats the purpose of using make instead of a simple script. Part of the point of make is to do the minimum work necessary, and if your target executable is present and not out of date with respect to its sources then there is no reason to force it to be rebuilt.