I've searched around for this issue, but nobody but me seems to have it, which is why I'll now ask.
If have this basic makefile:
CCPP = arm-none-linux-gnueabi-g++
CFLAGS = "-WALL -DPLATFORM_TARGET -DPRINT_MESSAGE"
LIB = lib/libarm.a
LDFLAGS = -lpthread
OBJECTS = $(wildcard ./*/*.o)
PROG = /exports/appl
MODULES = lib src
all: $(PROG)
$(CCPP) $(LDFLAGS) $(OBJECTS) $(LIB) -o $(PROG)
$(PROG): $(MODULES)
#for i in $(MODULES); do (cd $$i && $(MAKE) \
CCPP=$(CCPP) LDPP=$(CCPP) CFLAGS=$(CFLAGS) LDFLAGS=$(LDFLAGS)) || exit 1 ;\
done
clean:
#for i in $(MODULES); do (cd $$i && $(MAKE) clean) || exit 1 ; done
rm $(PROG)
lib:
ar cr ../lib/$(LIB) $(OBJECTS)
This works. It takes whatever source file is within lib and src and compiles and links it nicely together. (By using local makefiles found in these folders which I can post too if need be)
Anyway, what I WANT now, is add more -D directives conditionally.
I've tried:
ifdef ALLOW_BACKTRACE
CFLAGS += -DALLOW_BACKTRACE
LDFLAGS += -rdynamic
endif
and also:
ifdef ALLOW_BACKTRACE
CFLAGS := $(CFLAGS) -DALLOW_BACKTRACE
#endif
or by putting the whole thing in quotes etc...but each time I try, it brings up the help page of make, telling me that it can't 'recognize' the new define.
Any idea what I'm doing wrong?
Any help is much appreciated.
Okay, this should be a more correct version of your makefile, I can not test it though because I don't have your sources:
export CCPP := arm-none-linux-gnueabi-g++
# Note that -pthread is required for both compiling and linking.
export CFLAGS := -pthread -WALL -DPLATFORM_TARGET -DPRINT_MESSAGE
export LDFLAGS := -pthread
LIB := lib/libarm.a
PROG := /exports/appl
MODULES := lib src
all: $(PROG)
$(PROG): $(MODULES)
$(CCPP) -o $# $(LDFLAGS) ./*/*.o $(LIB)
$(MODULES) : % :
$(MAKE) -C $#
touch $#
clean-module.%:
$(MAKE) -C $* clean
clean : $(MODULE:%=clean-module.%)
rm -f $(PROG)
.PHONY: all clean clean-module.%
What I changed:
LDFLAGS = -lpthread: when building multi-threaded applications you need both an extra compiler and linker flag, which is what -pthread/-pthreads gcc options is.
Contents of OBJECTS = $(wildcard ./*/*.o) are only correct when $(MODULES) built correctly. Removed it.
$(PROG) commands actually build $(PROG) target as it should.
$(MODULES) commands build the modules by invoking make in the corresponding directory. And then they update the timestamp of the directory to force rebuild of $(PROG). Since it is a recursive make it can't know whether anything have actually been updated in the module, hence it need to trigger the rebuild of anything that depends on the modules.
I still have a feeling that this won't work for you because your original makefile is missing dependencies.
Try doing this -->
ifeq ($(ALLOW_BACKTRACE),1)
CFLAGS += -DALLOW_BACKTRACE
endif
You've got to be KIDDING me!
Ahem. I seem to have found the solution to my own problem. I don't quite get it, but whatever works, right?
Anyway, here's what I did:
CFLAGS += -Wall -DPLATFORM_TARGET -DPRINT_MESSAGE
ifdef ALLOW_BACKTRACE
CFLAGS += -DALLOW_BACKTRACE
LDFLAGS += -rdynamic
endif
LDFLAGS += -lpthread
$(PROG): $(MODULES)
#for i in $(MODULES); do (cd $$i && $(MAKE) \
CCPP=$(CCPP) LDPP=$(CCPP) CFLAGS="$(CFLAGS)" LDFLAGS=$(LDFLAGS)) || exit 1 ;\
done
First thing: -rdynamic needs to be the first flag in the linker, otherwise it refuses to work. (Don't ask me why, if anyone could enlighten me, be my guest.
Second: I had to put quotes around the expanded $(CFLAGS) in my actual build step. As soon as I did that, it worked like a charm...probably because it had a problem with the spaces.
Thanks to everyone, who went to the trouble of trying to help me.
Related
SEE UPDATES BELOW
Research Done: I'm finding learning how to evolve Makefiles from one situation to another is difficult. There are a ton of questions and answers out there but few of them actually show how a Makefile can evolve as your project changes. They also all seem to use various different techniques and idioms of Makefiles so translating between one question and another can be tricky when you are learning Makefiles for the first time, as I am.
Problem: My problem is that I have a project that started at as a flat directory structure but then is migrating to a structure with sub-directories. What I can't do is get my Makefile to along for the ride.
First I'll show what I created that works and then I show how I want it to evolve and how that doesn't work.
Flat Directory Structure, Working Makefile
I have project directory that has all my C files and one header file plus my Makefile:
project
Makefile
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Here is my Makefile (which works just fine):
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Targets
all: c8_dasm c8_asm c8_terp
c8_dasm: c8_dasm.o
$(CC) $(LDLIBS) c8_dasm.o -o $#
c8_asm: c8_asm.o
$(CC) $(LDLIBS) c8_asm.o -o $#
c8_terp: c8_terp.o
$(CC) $(LDLIBS) c8_terp.o -o $#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: chip8.h
c8_asm.o: chip8.h
c8_terp.o: chip8.h
.PHONY: clean
clean:
rm c8_dasm c8_asm c8_terp c8_dasm.o c8_asm.o c8_terp.o
I get all my .o files and my executables are created in the project directory.
Evolving The Project
But what I wanted to do is have my sources files (all .c and .h) in a src directory. I wanted to build into an obj directory and have the executables go in a bin directory. So my project would look like this:
project
src
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Makefile
Sub-Directory Structure, Makefile NOT Working
To accommodate the above, I changed my Makefile accordingly:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
MKDIR_P ?= mkdir -p
# Targets
all: $(BIN_DIR)/c8_dasm $(BIN_DIR)/c8_asm $(BIN_DIR)/c8_terp
$(BIN_DIR)/c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_dasm.o -o $#
$(BIN_DIR)/c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_asm.o -o $#
$(BIN_DIR)/c8_terp: $(OBJ_DIR)/c8_terp.o
$(MKDIR_P) $(dir $#)
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_terp.o -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
$(MKDIR_P) $(dir $#)
$(CC) $< -o $(OBJ_DIR)/$#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
$(OBJ_DIR)/c8_dasm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_asm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
rm $(OBJECTS)
Upon running this I get the following:
mkdir -p obj/obj/
gcc src/c8_dasm.c -o obj/c8_dasm.o
gcc -lm obj/c8_dasm.o -o bin/c8_dasm
ld: can't link with a main executable file 'obj/c8_dasm.o' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/c8_dasm] Error 1
I wanted to stop here and get some assistance because I fear I'm making this Makefile for complicated than it need be and I'm trying to avoid getting into bad habits.
I'm hoping to hear opinions about what I'm not conceptualizing correctly here.
FIRST UPDATE
I managed to take it bit by bit and get it mostly working. Here is what I ended up with:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Directories.
SRC_DIR = src
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
# Patterns for files.
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(SRC_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
# Targets
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: $(SRC_DIR)/chip8.h
c8_asm.o: $(SRC_DIR)/chip8.h
c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm $(OBJECTS)
rm -r $(BIN_DIR)
Of course, as I'm finding with Make this leads to other obscure problems. For example doing this:
make
make clean
works fine. Meaning all files are generated and the files are cleaned, including the bin directory.
However, if I do this:
make c8_dasm
make clean
This builds fine. But the clean fails to delete the bin directory (although it does delete the object files). This happens regardless of what individual executable I try to build.
No amount of searching is helping me find out why that is.
SECOND UPDATE
I found that problem was solved as well. It just required using the "-f" for the rm statements in the clean target.
THIRD UPDATE
To get the object file directory part working, I tried (from this: path include and src directory makefile) to construct my Makefile as follows:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -f $(OBJECTS)
I was able to condense the original three lines using chip8.h into one target but I have no way to know if that's correct. It compiles at least. I also changed the OBJECTS line to reflect the new OBJ_DIR I created.
However, this doesn't put the object files in the right place. It still puts them in the src directory rather than the obj directory.
This is why it makes sense to not do anything complicated with Makefiles. Just put the actual directory names in your commands. Never rely on wildcards.
People using C and C++ and using Makefiles spend too much time trying to get those to work rather than just actually getting things done. That's why you see so many of the questions that you see and why the answers vary so much.
In your specific case, your targets don't always have to contain the directory and that's part of the problem. The rules getting generated don't have an actual target in your file because of the directories you are prepending to everything. You have to think in terms of what is getting generated by each target: meaning, the output. So if c8_dasm is getting output, that's your target. The directory has nothing to do with that. So you need to remove all of your directory substitutions where they aren't needed.
But before doing that, ask yourself this: if your first solution was working, why change it? It's better to not even do directories when you're using Make. Just have everything in the same directory as you started off with. You can even see that this allows your Makefile to be much cleaner.
I believe I may have figured this out. Below is my Makefile. It seems to do what I want. It does the following:
Compiles all object files into the obj directory.
Compiles and links so that executables are generated in the bin directory.
Recognizes if any .c files are changed and recompiles accordingly.
Recognizes if the .h file is changed and recompiles all C files that reference it.
This seems to satisfy all the criteria but I can't tell if I've painted myself into some corner that I can't see yet.
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(OBJ_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/chip8.h
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -rf $(OBJ_DIR)
Stackoverflow is whining about too many comments, so I'll make this another "answer." After our back-and-forth to my original comment, your last comment is correct. That's what I wanted you to see.
Understand that you can't use Make to do what you want to do exactly.
So here's really the answer: You can't create multiple executables AND with only some of the object files applying to each one AND while using a directory structure. Make is in no way capable of handling that.
Right now you're trying to use Make in a way that it wasn't intended for which is why you're running into so many problems. If you keep playing around you're going to run into is a series of errors that say "duplicate symbol" because you will be compiling each of your files multiple times for each executable, assuming you follow most of the advice you'll find.
Check out this How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories? to see what I mean. That one works because all object files are being used to create a single executable. But as you've stated, that's not going to be the case for you. And that's what Make can't handle. That's why you're not finding an answer to that.
And while your chip8.h file is now not going to cause problems in terms of allowing you to compile, your Makefile with that third update would not recognize when the chip8.h file itself has changed. You would have to change a .c file to force a recompile so that changes to your .h were recognized. So you either have to stick with your second update or use something other than Make.
I'm updating the title and content here to make it clear that this particular question was asking something that I didn't see answered plainly elsewhere. The key notion is understanding that something that looks like a single target doing multiple things in a Makefile is actually multiple targets doing one thing each.
I will also remove some extraneous material since that ended up not being relevant.
Original Content
My problem is that I have a Makefile that is (apparently) not calling one of my sub-directory Makefiles correctly. I have a project structure like this:
quendor
src
cheap
cheap_init.c
Makefile
zmachine
main.c
Makefile
Makefile
The Makefile in the project root will refer to the Makefiles in the individual directories. Here is that core Makefile:
CC ?= gcc
CFLAGS += -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
CFLAGS += -O2 -fomit-frame-pointer
RANLIB ?= $(shell which ranlib)
AR ?= $(shell which ar)
export CC
export AR
export CFLAGS
export RANLIB
SRC_DIR = src
ZMACHINE_DIR = $(SRC_DIR)/zmachine
ZMACHINE_LIB = $(ZMACHINE_DIR)/quendor_zmachine.a
CHEAP_DIR = $(SRC_DIR)/cheap
CHEAP_LIB = $(CHEAP_DIR)/quendor_cheap.a
SUB_DIRS = $(ZMACHINE_DIR) $(CHEAP_DIR)
SUB_CLEAN = $(SUB_DIRS:%=%-clean)
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
$(SUB_CLEAN):
-$(MAKE) -C $(#:%-clean=%) clean
clean: $(SUB_CLEAN)
help:
#echo "Quendor"
.PHONY: $(SUB_DIRS) $(SUB_CLEAN) clean help
A key problem for me is this bit from the above:
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
I put the echo statements in just to show what's happening. Notice the $SUB_DIRS is correctly showing both directories, but when the Makefile runs it only shows src/zmachine. (The comments there indicate what I see during runtime.) The Makefile (apparently) doesn't process src/cheap.
The full output of the Makefile running is this (the first three lines there being my echo statements):
src/zmachine src/cheap
DIR:
src/zmachine
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C src/zmachine
cc -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O2 -fomit-frame-pointer -fPIC -fpic -o main.o -c main.c
ar rc quendor_zmachine.a main.o
/usr/bin/ranlib quendor_zmachine.a
** Done with Quendor Z-Machine.
The only thing I could think of initially was that perhaps after running the sub-makefile in src/zmachine, the Make process was either erroring out or thinking it was done. But the $(SUB_DIRS) part should have iterated through both directories, I would have thought.
So I'm a bit stuck as to how to proceed.
Extra Note: The "I would have thought" part of what I said was where I was incorrect. $(SUB_DIRS) was not being executed as I thought it was; the accepted answer has clarified this.
The way make works is, if you don't provide an argument, it will start by scanning the Makefile looking for the "default goal". The default goal is simply the first target it encounters (notice it's the first target, not targets).
In your case, the rule:
$(SUB_DIRS):
$(MAKE) -C $#
Is equivalent to:
src/zmachine src/cheap:
$(MAKE) -C $#
Which is equivalent to:
src/zmachine:
$(MAKE) -C $#
src/cheap:
$(MAKE) -C $#
So the first target make encounters is src/zmachine, and that's its default goal and the one that gets processed. The way to fix this is, as user657267 said in the comments, to add one target that you know will be processed first that would have the other targets (that you really want to build) as its prerequisites.
I want to use a makefile for my code which is going to use openmp. My source files are compiled and linked without any error. But when I run it, it uses just one processor, even though I adjust their number by for instance export OMP_NUM_THREADS=2.
The makefile is shown in the following. I would be grateful if somebody could please help me.
Best
CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o)))
CC = g++
DEBUG = -g
INTEL=icc
ifeq ($(notdir $(CC)),$(INTEL))
CCFLAGS=-openmp -lm -lstdc++
else
CCFLAGS=-fopenmp -lm -lstdc++
endif
LD_FLAGS :=-fopenmp -Wall $(DEBUG)
#CC_FLAGS := -Wall -c $(DEBUG)
MAIN: $(OBJ_FILES)
$(CC) $(LD_FLAGS) -o $# $^
obj/%.o: src/%.cpp
$(CC) $(CC_FLAGS) -c -o $# $<
.PHONY: clean
clean:
rm -f $(OBJ_FILES) *.o
Your defined variable CCFLAGS doesn't match the variable you're using CC_FLAGS in the actual compilation rules. When you clean up and run make do the compilation lines actually show the flags you set being passed? I'd expect they shouldn't, unless the code you have here isn't a direct copy of what you're running.
For ease of debugging, could you copy and paste a terminal transcript showing the compilation and linking happening?
So I am having a little bit of a tough time trying to figure out how to make my Makefile so that when I do make and it compiles a release version then later on do a make debug it compiles a debug version with the new -DDEBUG and -g set on gcc if the files have not been updated.
For example:
main.cpp is edited
run make
compiles main.cpp
run make debug
main.cpp is not recompiled because there were no changes even though the flags for compilation differ
Note I don't want to have to do a clean each time either because I dont want to have to recompile files if I do 2 makes in a row so setting clean as a dependency is not going to be a valid answer here
You may like to compile object files into a different directory depending on the build mode, e.g.:
# default mode, override with `make BUILD=release`
BUILD := debug
obj_dir := ${BUILD}
CFLAGS.debug := -g -O0
CFLAGS.release := -g -O3 -march=native -DNDEBUG
all : ${obj_dir}/test
# Example executable
${obj_dir}/test : ${obj_dir}/test.o
test.c :
echo "int main() { return 0; }" > $#
# Generic rules
${obj_dir} :
mkdir $#
${obj_dir}/%.o : %.c Makefile | ${obj_dir} # Also recompile when Makefile changes.
${CC} -c -o $# ${CPPFLAGS} ${CFLAGS} ${CFLAGS.${BUILD}} -MD -MP $<
${obj_dir}/% : Makefile | ${obj_dir} # Also re-link when Makefile changes.
${CC} -o $# ${LDFLAGS} $(filter-out Makefile,$^) ${LDLIBS}
clean :
rm -rf ${obj_dir}
-include $(wildcard ${obj_dir}/*.d)
${obj_dir}/*.d : ;
.PHONY: all clean
(Bonus feature: automatic dependency generation).
Usage:
[max#localhost:~/tmp] $ make
mkdir debug
echo "int main() { return 0; }" > test.c
cc -c -o debug/test.o -g -O0 -MD -MP test.c
cc -o debug/test debug/test.o
[max#localhost:~/tmp] $ make
make: Nothing to be done for 'all'.
[max#localhost:~/tmp] $ make BUILD=release
mkdir release
cc -c -o release/test.o -g -O3 -march=native -DNDEBUG -MD -MP test.c
cc -o release/test release/test.o
[max#localhost:~/tmp] $ make BUILD=release
make: Nothing to be done for 'all'.
First of all, you should not run make debug - that would mean, you want to build a different target (debug). But you don't, you want to build the same target, just with different options. That's what you do, you run a different option, a variable value
>make DEBUG=Y
When you run
>make
you also pass that variable really, just with the empty string as value.
Now, in order for this to work as you want in the Makefile, you would want to make it as if DEBUG was a prerequisite file, with recipes like this:
foobar.o: foobar.c DEBUG
gcc $(if $(DEBUG), -DDEBUG -g) -c $< -o $#
Of course, normally this won't work, because DEBUG is a variable, not a file. So you need a hack, that I call "dependable variables". It is basically a way to declare a variable to behave like a file. I describe this technique in one of my other answers:
How do I add a debug option to Makefile
I once did something like this, it looked like that (boiled down to the minimum):
EXE := a.out
SRC := $(wildcard *.c)
ifneq ($(MAKECMDGOALS),debug)
OBJ := $(SRC:.c=.o)
else
OBJ := $(SRC:.c=-d.o)
endif
.PHONY: all debug
all: $(EXE)
debug: CFLAGS += -g -DDEBUG
debug: $(EXE)
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
%.o %-d.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
The trick is to use two separate list of object files, and select one depending of the target.
I'm a little confused now. I'm trying to get the Makefile work but it breaks. I Hope someone can help me with this bad and frustrating time-killer.
I've written a small and lightweight part of a Compiler.
The project has the following structure:
/Compiler.cpp
/Makefile
/Buffer/
/Buffer/Makefile
/Scanner/
/Scanner/Makefile
/SymTable/
/SymTable/Makefile
When I'm compiling Buffer, Scanner and SymTable manual (changing the directory and typing 'make mode=release' it's no problem and each shared-library is compiled). But when I run the Makefile from within where the 'Master Makefile' /Makefile is, it fails and the terminal prints something like:
Buffer/libBuffer.so: file not recognized: File format not recognized
collect2: ld returned 1 exit status
make: \*** [Compiler] Error 1
Here is the listing of the Makefile of /Buffer/Makefile (the same for Scanner and SymTable):
CXX = g++
ifeq ($(mode),release)
CXXFLAGS = -g -fPIC -O3 -ffunction-sections -march=native
else
mode = debug
CXXFLAGS = -g3
endif
MODUL = Buffer
COMPONENTS = Buffer.h
MK_LIBRARY = lib$(MODUL).so
all: $(MK_LIBRARY)
$(MK_LIBRARY): $(COMPONENTS)
$(CXX) $(CXXFLAGS) -shared -o $# $^
clean:
rm -f $(MK_LIBRARY)
.PHONY: all
.PHONY: clean
The 'Master Makefile' looks like:
CXX = g++
ifeq ($(mode),release)
CXXFLAGS = -g -O3 -ffunction-sections -fwhole-program -march=native
else
mode = debug
CXXFLAGS = -g3
endif
TARGET = Compiler
COMPONENTS = $(TARGET)
DIRS = Buffer Scanner SymTable
MAKE = make
MFLAGS = mode=$(mode)
all: $(COMPONENTS)
$(TARGET): Compiler.cpp libBuffer.so libScanner.so libSymTable.so
$(CXX) $(CXXFLAGS) -IBuffer -IScanner -ISymTable \
-LBuffer -LScanner -LSymTable \
-lBuffer -lScanner -lSymTable -o $# Compiler.cpp
libBuffer.so: force_look
cd Buffer; $(MAKE) $(MFLAGS)
libScanner.so: force_look
cd Scanner; $(MAKE) $(MFLAGS)
libSymTable.so: force_look
cd SymTable; $(MAKE) $(MFLAGS)
clean:
rm -f $(COMPONENTS)
#for d in $(DIRS); do (cd $$d; $(MAKE) clean ); done
check:
#for d in $(DIRS); do (cd $$d; $(MAKE) check ); done
force_look:
true
.PHONY: all
.PHONY: clean
.PHONY: check
I hope some has an answer for me! Thanks!
There's something very weird about this part:
MODUL = Buffer
COMPONENTS = Buffer.h
MK_LIBRARY = lib$(MODUL).so
$(MK_LIBRARY): $(COMPONENTS)
$(CXX) $(CXXFLAGS) -shared -o $# $^
This rule tries to build libBuffer.so out of Buffer.h, the header file. How can this possibly work, without the definitions of the things in Buffer.cc? I would do it this way:
lib%.so: %.o
$(CXX) $(CXXFLAGS) -shared -o $# $^
EDIT:
You have the definitions of Buffer in Buffer.h? All right, you have more than one problem, and the only way to solve them is to do what almost always works: retreat to a simpler problem and solve that first. Can you make Buffer.o? And can you then link that into your executable (bypassing libBuffer.so)? And if not, can you write a "HelloWorld" in Buffer/, and link Buffer.o into that?