I want to compile my program both to linux and windows using g++ and mingw respectively. The only difference between the compilations is the compiler to use and output file name.
A single make command should produce both output files. What is the best way to achieve this with as little duplications in the makefile as possible?
How about this:
linux-name: CC:=g++
windows-name: CC:=mingw
linux-name windows-name:
$(CC) whatever -o $#
EDIT:
What I wrote above is only the new part of the makefile; I assumed that the rest of the makefile was implied. To be more explicit:
all: linux-name windows-name
linux-name: CC:=g++
windows-name: CC:=mingw
linux-name windows-name: foo.o bar.o baz.o SomethingElse
$(CC) $(CCFLAGS) whatever $^ -o $#
%.o: %.cc
$(CC) $(CFLAGS) -I$(INC_DIR) whatever -c $< -o $#
SomethingElse:
build somehow
Related
There are three programs build by this Makefile. They follow the same pattern, but produce different build commands when run. Specifically, I require compilation with c++11 but can only achieve this on one of the build commands. Why is this?
Makefile:
CXX=g++
RM=rm -f
CFLAGS=-std=c++11 -g -Wall $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SOURCES=generic_queue.cpp map_compare.cpp vector_search.cpp
OBJS=$(SOURCES:.cpp=.o)
all: $(SOURCES) generic_queue_test list_of_lists map_compare_test vector_search_test
# Note that $(CFLAGS) is used in the $(CXX) ... command
# each time that a .o file is built.
vector_search_test: $(OBJS) vector_search_test.o
$(CXX) $(LDFLAGS) -o vector_search_test vector_search_test.o $(LDLIBS)
vector_search_test.o: vector_search.cpp vector_search.h
$(CXX) $(CFLAGS) -c vector_search.cpp -o vector_search_test.o
generic_queue_test: $(OBJS) generic_queue_test.o
$(CXX) $(LDFLAGS) -o generic_queue_test generic_queue_test.o $(LDLIBS)
generic_queue_test.o: generic_queue.cpp generic_queue.h fixed_priority_queue.h
$(CXX) $(CFLAGS) -c generic_queue.cpp -o generic_queue_test.o
list_of_lists: $(OBJS) list_of_lists.o
$(CXX) $(LDFLAGS) -o list_of_lists list_of_lists.o $(LDLIBS)
list_of_lists.o: list_of_lists.cpp list_of_lists.h
$(CXX) $(CFLAGS) -c list_of_lists.cpp -o list_of_lists.o
map_compare_test: $(OBJS) map_compare.o
$(CXX) $(LDFLAGS) -o map_compare map_compare.o $(LDLIBS)
map_compare.o: map_compare.cpp map_compare.h
$(CXX) $(CFLAGS) -c map_compare.cpp -o map_compare.o
clean:
$(RM) $(OBJS) generic_queue_test.o list_of_lists.o map_compare.o
dist-clean: clean
$(RM) generic_queue_test list_of_lists map_compare
Output:
g++ -c -o generic_queue.o generic_queue.cpp
g++ -std=c++11 -g -Wall -pthread -m64 -I/usr/include/root -c map_compare.cpp -o map_compare.o
g++ -c -o vector_search.o vector_search.cpp
We see that only the second g++ command fully utilizes CFLAGS variable. Why? Does it have to do with the $(shell ...) portion of the CFLAGS variable?
Edit:
Was able to solve my problem by changing the name of the object file vector_search_test.o to vector_search.o Why did that work?
You have a couple of bugs in your makefile, adding up to this behavior.
First consider OBJS, which contains
generic_queue.o map_compare.o vector_search.o
These files are prerequisites of other targets, but you never actually use generic_queue.o or vector_search.o. Bug #1: you have extra prerequisites by mistake.
These files are prerequisites of other targets, so Make must build them. But how? You have provided rules for three object files:
vector_search_test.o: vector_search.cpp vector_search.h
...
generic_queue_test.o: generic_queue.cpp generic_queue.h fixed_priority_queue.h
...
list_of_lists.o: list_of_lists.cpp list_of_lists.h
...
map_compare.o: map_compare.cpp map_compare.h
...
That last one will do for map_compare.o, but you have given no rules for generic_queue.o or vector_search.o (and there's really no reason you should, since you never use them). But Make knows how to perform certain standard builds, such as foo.cpp => foo.o. If you don't provide a rule, Make will use its implicit rule, which works out to something like this:
generic_queue.o: generic_queue.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c generic_queue.cpp -o generic_queue.o
This is very similar to the rules you wrote. In fact, you probably wouldn't have noticed the difference -- and you could have omitted your rules and let Make rely on this one, but Bug #2, you added your flags -std=c++11 -g -Wall whatever to the wrong variable. Make uses CXXFLAGS to hold flags for the C++ compiler; you added yours to CFLAGS, which is for the C compiler.
(I've left out pattern rules and automatic variables since you don't seem to know about them-- I urge you to learn them, they're very useful, but that's for another day.)
If I have 3 files, function.h, function.c and my_program.c which calls a method in function.h all in the same directory, what would be the best way to write a makefile so that I end up with a my_program.bc that would actually run when I type in lli my_program.bc? (I need to run a user defined pass that would insert stuff into the functions - should I run the pass on function.bc and test.bc, or should I link before running the pass?)
I've tried llvm-link function.bc my_program.bc with no luck. I feel I'm either missing something simple or going about the whole thing wrong.
Current terrible none-working makefile:
.PHONY: all clean
CC = clang
CFLAGS = -std=gnu99 -D_POSIX_C_SOURCE=200809L -g -Wall
IRFLAGS = -O3 -emit-llvm
TARGET = test
DEPS = functions.h
all: $(TARGET)
bc: test2
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
%.bc: %.c $(DEPS)
$(CC) $(IRFLAGS) -c -o $# $<
test2: test.bc functions.bc
llvm-link -o test2.bc $< functions.bc
test: test.o functions.o
$(CC) $(CFLAGS) -o $# $^
clean:
$(RM) $(TARGET) *.o *.bc
Why not just write a normal Makefile to produce the desired executable,
then use wllvm?
Shameless plug for wllvm:
https://github.com/SRI-CSL/whole-program-llvm
I do not use lli, so I would be interested to hear about how it resolved
any reliance on stdlibc that your program may have.
I'm trying to understand deeply how makefiles work.
For example, I've the following one:
CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -rf *.o test_int_array *.dSYM
The part that I really don't understand fully is :
...
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).
-o means to write the output to the specified file. Which file in this case?
I understood that $# (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?
What does $< mean?
Could you please explain step by step how the make tool would interpret those two statements?
I think I understood this part more or less:
...
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $# from the $(OBJS) files on the right (stated using the option $^).
Is $(CFLAGS) needed in both cases? Does the order matter?
In the example:
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
$# is the filename of the target for this rule: test_int_array.
$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o
In the example:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$< is the name of the first prerequisite: %.c
$# is the filename of the target for this rule: %.o
$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.
In a Makefile, each rule follows this format:
resulting_file : source_files
steps to get resulting_file from source_files
What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.
%.ext : %.ext2
is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.
%.c : %.o
is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)
This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.
Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96
You can find out about $#, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101
$#: the entire lefthand
$<: the first file in the righthand
$^: the entire righthand list of files, space separated.
Condition 0:
Say, I have several source codes, a.c, b.c, ..., z.c, and I want a rule to have each of them compiled. Here is a solution:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Condition 1:
Then I introduce a header c.h used in c.c, and another header e.h used in c.c and e.c, and things become complex:
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
c.o: c.c c.h e.h
$(CC) -c -o $# $(CFLAGS) $<
e.o: e.c e.h
$(CC) -c -o $# $(CFLAGS) $<
My question:
Based on the solution of condition 1, is there something like add_dependency in make to simplify the solution and obtain something like the following one?
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
add_dependency(c.o, c.h e.h)
add_dependency(e.o, e.h)
Or, what do you think is a better solution to condition 1?
EDITED:
Thanks for the kind notice #ctheo :)
Yes I did have a look at autotools and understood that shall satisfy all my needs. However what I'm dealing with is an existing project and its Makefile contains other directives dealing with codes in C++, and I think for now I'd better just modify a few lines instead of port the whole Makefile to autotools, unless I couldn't find a satisfying solution without introducing autotools. :)
At first I did not expected to exist a solution for this. It seemed to me that it was covered by autotools. However, after some search, I found this section of GNU/make manual.
It states that :
One file can be the target of several rules. All the prerequisites mentioned in all the rules are merged into one list of prerequisites for the target.
So there is a solution for your query
c.o: c.h e.h
e.o: e.h
%.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
Thanks for insisting. I learned something today :)
In addition, the .o files in your example all depend on a .h file with the same stem, so you can generalise that part of your rules too:
c.o: e.h
%.o: %.c %.h
$(CC) -c -o $# $(CFLAGS) $<
This way, your “normal” situations are covered entirely by the rule that triggers compilation and your “unusual” situations stand out because those are the only additional rules.
I have added another rule to a Makefile to attempt to build a C shared library that uses SWIG to wrap the functions for Java using JNI
The additional rule looks like this (basically lifted from one of the SWIG java examples)
java: $(program_C_SRCS)
$(SWIG) -java $(SWIGOPT) $(INTERFACEPATH)
$(CC) -c $(CFLAGS) $(JAVACFLAGS) $(program_C_SRCS) $(ISRCS) $(CPPFLAGS) $(JAVA_INCLUDE)
$(JAVALDSHARED) $(CFLAGS) $(program_C_OBJS) $(IOBJS) $(JAVA_DLNK) $(LDFLAGS) -o $(JAVA_LIBPREFIX)$(TARGET)$(JAVASO)
javac *.java
problem I have is that my VPATH doesn't seem to work with the *.c files anymore
I noticed that this rule causes all the .c files to compiled as one call to gcc rather than a separate call to gcc for the compilation of each .o file
my previous rules for compilation without any JNI stuff look like this:
.PHONY: all clean
all: $(program_DEBUG_NAME) $(program_RELEASE_NAME)
# original rule to build library in src dir (no longer inc. in all)
$(program_NAME): $(program_C_OBJS)
$(LINK.c) -shared -Wl,-soname,$# $^ -o $#
# new rules to build debug/release libraries and place them in relevant build
# dirs
$(program_DEBUG_NAME): $(DEBUG_OBJS)
$(DEBUG_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/debug/$#
$(program_RELEASE_NAME): $(RELEASE_OBJS)
$(RELEASE_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/release/$#
# rule to build object files (replaces implicit rule)
$(BUILD_DIR)/debug/%.o: %.c
$(DEBUG_LINK.c) $< -c -o $#
$(BUILD_DIR)/release/%.o: %.c
$(RELEASE_LINK.c) $< -c -o $#
and these work with VPATH no problem
my VPATH statement looks like this:
VPATH = ../../pulse_IO/src ../../../g2/src
Look at your rule:
java: $(program_C_SRCS)
...
$(CC) -c $(CFLAGS) $(JAVACFLAGS) $(program_C_SRCS) ...
...
Suppose program_C_SRCS is foo.c, and the path is somewhere/foo.c. Without VPATH, this rule doesn't run at all because Make can't find foo.c. With VPATH, Make finds it, and knows that the real prereq is somewhere/foo.c. But you have $(program_C_SRCS) in your rule:
java: somewhere/foo.c
...
$(CC) -c $(CFLAGS) $(JAVACFLAGS) foo.c ...
...
This fails because there is no foo.c (locally).
Try this:
java: $(program_C_SRCS)
...
$(CC) -c $(CFLAGS) $(JAVACFLAGS) $^ ...
...
(The use of automatic variables like $^ is the reason your previous rules worked.)