makefile - separate folders - makefile

I want to compile my source files twice with different flags each time. Besides that I need to have these executables which I'll acquire after the compilation in different directories (so I want 'make' to create two folders and put into every folder an executable).
I think that them main problem is that I don't know how to main object files. Think that we can create them with different names (because every set of .o files should somehow differ from the another which has different flags) or put them in the directories where we want to have executables.
Still I have no idea how to do it in elegant way :/
Any help greatly appreciated :)

You haven't given us many details, so I'll suppose you have two source files, foo.c and bar.c, and you're building in two directories, red/ and blue/. Here is a crude makefile that will do the job:
OBJS := foo.o bar.o
RED_OBJS := $(addprefix red/,$(OBJS))
BLUE_OBJS := $(addprefix blue/,$(OBJS))
$(RED_OBJS): red/%.o : %.c
$(CC) -c $< -o $#
$(BLUE_OBJS): blue/%.o : %.c
$(CC) -c $< -o $#
red/red_exec: $(RED_OBJS)
$(CC) $< -o $#
blue/blue_exec: $(BLUE_OBJS)
$(CC) $< -o $#

Related

Evolving a Makefile From Flat Directory Structure to Sub-Directory Structure

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.

Create object files in one folder from different source folders

I am creating a Makefile of a Keil based project. I have a working Makefile now, but I have manually written rules for all the source files, something like this:
out/abc.o: ../../../src/modules/abc.c
ARMCC -o $# $(FLAGS) $^
out/def.o: ../../../src/utilities/def.c
ARMCC -o $# $(FLAGS) $^
out/xyz.o: src/xyz.c
ARMCC -o $# $(FLAGS) $^
which has become kinda long. The object files need to be in one directory(/out), but the source files are in different levels and in various folders like utilities, modules etc. Is there a way to shorten my Makefile so that it scans these different levels of source files and creates the object files?
EDIT:
A follow-up question to the answer. My linker rule is something like this, along with the VPATH addition. I added one directory to VPATH and others are still explicitly compiled.
OBJECT_FILES=out/abc.o out/def.o out/xyz.o
out/binary.axf: $(OBJECT_FILES)
ARMLINK $(MANY_FLAGS) $^ -o $#
VPATH=../a/b/c/module
out/%.o : %.c
$(CC) $(C_FLAGS) $(INCLUDE_PATH) -o $# --depend out/%.d $<
I now get an error that there is no rule for abc.o. abc.c which is present in the directory specified in VPATH under module
*** No rule to make target `out/abc.o', needed by `out/binary.axf'. Stop.
You can use VPATH for this. It can search a list of directories for source files. Assuming you can come up with the list of directories:
VPATH = ../../../src src
CC = ARMCC
out/%.o : %.c
$(CC) -o $# $(CFLAGS) -c $<

Makefile - How to get the path of src/header files

Can someone explain me how i do a Makefile getting the source files from a folder named src and the header files from a folder named headers? And then the executable files and the object files being stored on the current folder? Just a basic example to help me out ;). thanks
Like this?
OBJ := foo.o bar.o
thing: $(OBJ)
$(CC) $^ -o $#
%.o: src/%.c
$(CC) -c -Iheaders $< -o $#

Makefile - Pattern Rule as a dependency

I've ha makefile with following entries. Will the first rule depend on the secon rule ? So that it builds all the .o files from second files ?
all:$(PROG)
$(PROG): *.o
$(LD) -o $(PROG) -c $< $(LFLAGS)
%.o : %.c
$(CC) $(CFLAGS) -o $# -c $<
To be specific if i invoke 'make all' will it invoke the second rule if no *.o files were found ?
All other Variables have usual meaning .
No, that will not work. When you run your makefile for the first time, are there any .o files? No. So the expression *.o will expand to nothing.
Of course, your recipe for $(PROG) doesn't actually use any of the object files anyway, as written.
You can do something like this (although personally I prefer to simply list the files out by hand; it's not very common to create all new files so it's not much effort, and it's safer than just trying to grab every file in the directory):
SOURCES := $(wildcard *.c)
OBJECTS := $(SOURCES:%.c=%.o)
$(PROG): $(OBJECTS)

Make searches dependencies in the wrong place

I'm relatively new to (GNU) Make, and find it incedibly difficult. I consider switching to SCons, but still, I'd like to understand.
I have a makefile in a folder, that contains subdirectories ./src, ./obj/[release|debug] and ./bin[release|debug]. The makefile should be able to grab the C++ sources in ./src, compile them into object files in the appropriate ./obj directory, and link these object files and put the result in the appropriate ./bin directory. Here is my makefile (edited for simplicity):
CONFIG = release
#CONFIG = debug
OBJS = Container.o
OBJDIR = obj/$(CONFIG)
BINDIR = bin/$(CONFIG)
VPATH = src $(BINDIR)
vpath %.o $(OBJDIR)
.PHONY: release
release: $(OBJS)
$(CXX) $(LXXFLAGS) -o $(BINDIR)/$# $^
Container.o: Container.cpp Container.hpp
$(CXX) -c $(CXXFLAGS) -o $(OBJDIR)/$# $<
The first time I run make, the "release" target will search for "Container.o" in the current folder, as well as in $(OBJDIR). Failing to find it, the secong target will be correctly executed, generating the object file in the correct folder. The "release" target will then execute, but the linker will complain that "Container.o" is not found...
The second time I run make, the "release" target will search for "Container.o" and find it in $(OBJDIR). The linker will then execute correctly (the path where "Container.o" has been found is prepended to the filename).
Is there a way to make it work in a single pass? It drives me crazy!
Make does have a long learning curve, and you're attempting something tricky (and which runs right into one of Make's big weaknesses, poor wildcard handling). I'm not sure that my answer will help more than confuse, but at least it will solve your specific problem.
If you want to use the CONFIG approach, this will do it:
CONFIG = release
#CONFIG = debug
OBJS = Container.o
TRUE_OBJS = $(addprefix obj/$(CONFIG)/, $(OBJS))
vpath %.cpp src
.PHONY: $(CONFIG)
$(CONFIG): bin/$(CONFIG)/$(CONFIG)
bin/$(CONFIG)/$(CONFIG): $(TRUE_OBJS)
$(CXX) $(LXXFLAGS) -o $# $^
$(TRUE_OBJS): obj/$(CONFIG)/%.o : %.cpp
$(CXX) -c $(CXXFLAGS) -o $# $<
But you can do without it (and without the chore of editing the makefile whenever you want to change configurations):
OBJS = Container.o
vpath %.cpp src
.PHONY: release debug
release: bin/release/release
debug: bin/debug/debug
bin/release/release: $(addprefix obj/release/, $(OBJS))
bin/debug/debug: $(addprefix obj/debug/, $(OBJS))
bin/release/release bin/debug/debug:
$(CXX) $(LXXFLAGS) -o $# $^
obj/release/%.o obj/debug/%.o: %.cpp
$(CXX) -c $(CXXFLAGS) -o $# $<

Resources