Library Linking - makefile

I am trying to learn to C programing using Zed Shaw's Learn C the hard way. I have been working on ex26 where we create a program "devpkg" used to install software. This exercise requires installing Apache Portable Runtime library. After writing the code for this exercise I could not get program to compile using the following makefile:
PREFIX?=/user/local
CFLAGS=-g -Wall -I${PREFIX}/apr/include/apr-1 -I{PREFIX}/apr/include/apr-util-1
LDFLAGS=-L${PREFIX}/apr/lib -lapr-1 -pthread -laprutil-1
all: devpkg
install: all
install -d${DESTDIR}/${PREFIX}/bin/
install devpkg ${DESTDIR}/${PREFIX}/bin/
clean:
rm -f *.o
rm -f devpkg
rm -f *.dSYM
This makefile did not seem to work as when I used "$make devpkg" not all of the APR library functions were declared. As a side note I am running this on a Ubuntu virtual machine. A solution given in the text says to alter a config file and then "run ldconfig" to help the linker find the appropriate library.
I do not understand the man page for ldconfig well enough to correctly utilize the function. How do run ldconfig correctly?
Also after some digging I found a reference that using "LDLIBS" instead of "LDFLAGS" in the makefile fixed the problem. I altered the makefile and the program compiled.
What is the difference between "LDFLAGS" and "LDLIBS" that allowed the C compiler to correctly link to the APR library? Is there a handy list of commands somewhere that can help me better understand how a makefile is correctly generated?
Thanks for your time.

From the GNU Make Manual, section 10.2 Catalogue of Implicit Rules:
Linking a single object file
n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is '$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)'.
As you can see, LDFLAGS comes before your object file and LDLIBS after. Sometimes that order can matter - apparently it does in your case.
Editorial note: While it might sometimes be convenient to use make's implicit rule support, it almost always ends up more confusing down the road. I'd urge you to write a complete makefile - it'll help you understand what's going on better and hopefully avoid this sort of problem in the future.

I just wanted to add this answer as an alternative to changing "LDFLAGS" to "LDLIBS". The above solution did work in my case but I found an alternative (though less direct) solution before I saw this thread which others may find useful or interesting. When compiling I was seeing lots of "undefined reference" errors e.g.:
/MyCode/LCTHW/devpkg/devpkg.c:18: undefined reference to `apr_pool_initialize'
After much trial and error, I changed the makefile thus (still using LDFLAGS):
CC=gcc
PREFIX?=/usr/local
CFLAGS=-g -Wall -I$(PREFIX)/apr/include/apr-1 -I$(PREFIX)/apr/include/apr-util-1
LDFLAGS=-L$(PREFIX)/apr/lib -lapr-1 -laprutil-1 -pthread
OBJECTS=bstrlib.o db.o shell.o commands.o devpkg.o
all: devpkg
devpkg: $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o devpkg $(LDFLAGS)
install: all
install -d $(DESTDIR)/$(PREFIX)/bin/
install devpkg $(DESTDIR)/$(PREFIX)/bin/
clean:
rm -f *.o
rm -f devpkg
rm -rf *.dSYM
I then had to add a .conf file to /etc/ld.so.conf.d containing the path to the apr libraries, namely
/usr/local/apr/lib
And then run
sudo ldconfig
so the system would pick up the new .conf file and so know where to find the library. From what I have read, it seems this last step was necessary because the library wasn't stored in /usr/local/lib. If I remove the .conf file and re-run ldconfig to update, the program compiles but then fails to find the libraries at run-time (whether compiled with my makefile or OP's).
While I don't fully understand my solution, it at least allowed me to compile and run the program with no errors. Hopefully this solution will be of interest to others, and maybe somebody more knowledgeable will be able to explain in more detail why it works.

Related

How to build Qhull into Javascript with Emscripten?

I've been trying to build Qhull for use on the net, and to be honest. I'm completely lost. I've already installed the Emscripten SDK, and I've tried reading through the guides. From what I can gather, it seems that there are two ways to compile a large project like this one: I can either pass the files as arguments to emcc, or I can make my own custom Makefile that somehow does that for me. But I can neither figure out how to pass multiple files as arguments, nor how Makefiles work.
After scouring the web, I managed to find this port of an old Qhull version, which comes with its own Makefile:
QHULL_PATH = ./src/libqhull
TARGET = qhull.js
EMCC = ../emscripten/emcc
PREJS = ./src/pre.js
POSTJS = ./src/post.js
MAIN = ./src/main.c
EXPORTJS = "['_run_qhull']"
CFLAGS = -O1
SOURCES := $(shell find $(QHULL_PATH) -type f -name '*.c')
all: $(TARGET)
#echo "Done"
$(TARGET): $(SOURCES) $(PREJS) $(POSTJS) $(MAIN)
$(EMCC) $(CFLAGS) $(SOURCES) $(MAIN) -s EXPORTED_FUNCTIONS=$(EXPORTJS) --pre-js $(PREJS) --post-js $(POSTJS) -o $(TARGET)
clean:
rm -rf $(TARGET)
Unfortunately, the Makefile is in the Unix format, which I only figured out after about two hours of frustration. I don't know how to make it work on Windows.
So, what can I do to get the latest version of Qhull running in Javascript?
I'm using Windows, and my current IDE is Dev-C++.
So if you're new to compiling, using emscripten to compile a large library is going to be a big challenge. I suggest reading through the emscripten docs on compiling.
It looks like Qhull has both a MakeFile and a CMakeLists.txt. I suggest trying CMake.
The typical way to use CMake with emscripten on linux is something like this:
mkdir embuild
cd embuild
emcmake cmake ..
emmake make
I've never compiled on Windows (I use linux), but I believe that (at least when using Cmake) it is similar.
That probably won't work on the first try.
If (after many tries) you can't get it working, you could try compiling qhull manually with emcc. It looks harder at first, but in the long run I usually get fewer errors.

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?
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.
Check out the answer:
Set up my makefile to compile C with just "make"
YOu have to specify in the Makefile the file you want to create in this case stack_raster.exe and the objective file in this case stack_raster.cpp and specify the command line arguments you normally pass for compiling. So the Makefile would be something like:
CXX=g++
stack_raster.exe: stack_raster.cpp
g++ -o stack_raster.exe stack_raster.cpp -lgdal -lboost_filesystem -lboost_system
all: clean stack_raster.exe
clean:
rm -f stack_raster.exe

`make` doesn't notice modifications in a Rust module - how to better integrate Rust into the build?

In a simple embedded project, i have two files main.rs and module.rs. To build the project, I use something similar to this:
all: main.o
$(CC) main.o $(LDFLAGS)
%.o: %.rs
$(RUSTC) $(RUSTFLAGS) -o ${#} ${<}
If only module.rs is changed, make all won't recompile my Rust code. How can I fix this?
I'm posting a suboptimal self-answer as a first step, but would love to see better ways.
The best way to use Make is to encode every single dependency into the Makefile. That's what gives Make the power to know what to rebuild in order to reach a goal state.
To do this for a C project, you'll often use something like the GCC command line option -M. This brings the compiler into the mix as it's the best tool to parse C source code and understand the dependencies between the
files.
There is actually an equivalent switch for rustc, the Rust compiler: --emit=dep-info. When you run this on a source file, it will output a file with the extension .d, which contains an almost-Makefile-compatible list of dependencies. If you had a main.rs that referenced the module foo.rs, it would output something like:
main.d: main.rs foo.rs
With a bit of sed tweaking you can get this to play nicely. You can then include this in your Makefile:
main.o:
rustc -o $# $<
main.d: main.rs
rustc --emit=dep-info $<
# Add the object file as a rule
gsed 's/:/ $(#:.d=.o):/' -i $#
-include main.d
Here, I've specified main in a few parts, but I believe that you can easily modify them into pattern rules.
The pragmatic solution is to just use Cargo, the Rust build tool and package manager. Let it deal with dependencies (both local modules and other crates).
libbar.dylib: target/debug/libbar.dylib
cp $< $#
.PHONY: target/debug/libbar.dylib
target/debug/libbar.dylib:
cargo build --verbose
Here, I've marked the rule as PHONY, which says "always run this rule". I've added --verbose to have Cargo print out what it is doing so you can verify when things are rebuilt.
I'd recommend dropping off the cp step if you can and instead just use the nested path, but the copy might be needed if other things rely on the current location.
The pattern
%.o: %.rs
is familiar from building C projects, but that's not the only way a target can be written. Specific to the setup above, this would fix the situation:
main.o: main.rs module.rs
$(RUSTC) $(RUSTFLAGS) -o main.o main.rs
A noteworthy difference to the original code is that the names of the inputs is not really what matters for the command. We can generalize this as follows:
main.o: $(wildcard *.rs)
$(RUSTC) $(RUSTFLAGS) -o ${#} ${#:.o=.rs}
This is a start, but it still has some downsides I couldn't get rid of:
The main.o: part is hardcoded. If there are multiple top-level modules to compile, there would be code duplication
All Rust files will be considered for all top-level modules, due to the wildcard. In other words, changing any Rust file will require a full recompilation.

make command with math library

I need to just run the make command for makefile. But when I run this make command I get the error that "undefined reference to `log'" because I know this fact that it doesn't include math Library and we have to include at runtime. I know that if I run this using gcc comiler then i can write -lm at the end, it will include math library. My problem is I need to run it using make command that is- make lu.
In this if I write make lu -lm it is not linking math library. Please help
Using this link How to use LDFLAGS in makefile
I updated my make file but still same problem persists. Please Help.
SHELL=/bin/sh
BENCHMARK=ep
BENCHMARKU=EP
include ../config/make.def
OBJS = ep.o ${COMMON}/c_print_results.o ${COMMON}/c_${RAND}.o \
${COMMON}/c_timers.o ${COMMON}/c_wtime.o
include ../sys/make.common
LDLIBS=-lm
LDFLAGS=-lm
${PROGRAM}: config ${OBJS}
${CLINK} ${CLINKFLAGS} -o ${PROGRAM} $(LDFLAGS) $(LOADLIBES) ${OBJS} ${C_LIB}
ep.o: ep.c npbparams.h
${CCOMPILE} ep.c
clean:
- rm -f *.o *~
- rm -f npbparams.h core
Why does your makefile refer to all sorts of variables that don't exist, like LOADLIBES, C_LIB? Why do you set variables that you never use, like LDLIBS?
The reason it doesn't work is that you're putting the library reference in the LDFLAGS variable, which comes early in your link command before any of your object files. So when the linker goes to link in the math library it thinks that it's not needed because nothing is using it yet.
You have to put libraries at the end of the link line.
Since you already have the C_LIB variable at the end which you are not using, if you add:
C_LIB = -lm
then it should work.

Portable make clean rule

I am writing a smallish C program for fun. I decided to just use MinGW (only C), make and Notepad++ as an exercise in not using fancy IDEs for a change. So far so good and fun.
(MinGW == I am working on Windows.)
Now since the program compiles against vanilla C I thought of making it fully portable. MinGW make and gcc is smart enough create a program from the rule:
myprog: myprog.o other.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $#
Obviously, since I am on windows the compiler creates myprog.exe. This is quite smart and makes the entire thing quite portable.
As far as standard targets go I want to at least implement clean since I actually use that rule. Now the clean target, that actually works on Windows looks like this:
clean:
rm myprog.exe *.o
This rule will definitely not work in a POSIX environment, because programs don't have extensions there. (PSOIX: think GNU/Linux)
Is there a portable way implement a clean without to much make fu?
So far I have not found any really useful documentation around this issue. If you look at how autoconf and automake tackle the issue, they introduce the pattern #EXEEXT#. But that relies on lengthy configure code testing the environment.
Define the binary name as a variable (optionally deduce it from the name of the source file defining "main()" with a simple egrep command):
EXE_EXT_LINUX:=
EXE_EXT_WINDOWS:=exe
EXE_EXT:=$(EXE_EXT_$(PLATF))
BINARY_NAME:=$(notdir $(basename $(shell egrep -r -l --include=*.cpp '^[ \t]*?int[ \t]*?main[ \t]*?\(') ) )$(EXE_EXT)
And use this macro instead of hardcoded name
If solved it the following way:
UNAME = $(shell uname -o)
ifeq ($(UNAME), Msys)
EXEEXT = .exe
endif
clean:
rm *.o myprog$(EXEEXT)
It solved the issue quite nicely. Although it is not totally 100% portable it works most common cases.

Resources