I have a problem with linking all the generated obj files into an executable with my current make setup. My directory structure is as follows (provided for reference):
root
bin
include
project1 ... projectN
Makefile
root/bin
project1 ... projectN
bin
obj
Project1 (for example)
include
src
Makefile
As you can see, I store multiple subprojects under the same directory and use recursive calls to make to build each project. First it gathers all the source and header files from a specific project and it compiles them storing the resulting obj files in root/bin/project/obj. From here, I want to link all the obj files and generate an executable file that will be stored under the root/bin/project/bin directory.
The problem is that, by using the current Makefile configuration, my linker (MSVC link.exe) can only see the first obj file in the obj dir. Makefile provided below to see the compile and link commands:
# expands to root/bin/projname/bin
TARGET_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/bin
#expands to root/bin/projname/obj
OBJ_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/obj
# expands to a list of all the obj files created from the source files (a.obj, b.obj..)
OBJECTS := \
$(notdir $(patsubst %.cpp,%.obj,$(patsubst %.c,%.obj,$(SOURCES))))
SOURCES := $(wildcard src/*.c) $(wildcard src/*.cpp)
# default target
all: dirs $(TARGET).exe
# Link
$(TARGET).exe: $(OBJ_DIR)/$(OBJECTS)
$(LNK) $(LIB_PATH) $(LIBS) /OUT:$(TARGET_DIR)/$# $(OBJ_DIR)/$(OBJECTS)
# Compile
$(OBJ_DIR)/$(OBJECTS): $(SOURCES)
$(CC) /c $(CFLAGS) $(INCLUDES) /Fo$(OBJ_DIR)/ /EHsc $(SOURCES)
.PHONY: build
dirs:
$(MKDIR) $(TARGET_DIR)
$(MKDIR) $(OBJ_DIR)
$(MKDIR) $(TEST_DIR)
The error I am encountering is as follows, during the linking process:
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\\..\..\VC\vcvarsall.bat" x86_amd64 > NUL && link /NOLOGO /MACHINE:X64 /LIBPATH:"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib\x64" /DEFAULTLIB:shell32.lib /OUT:../bin/project1/bin/project1.exe ../bin/project1/obj/main.obj sort.obj
As you can see, it only links against the first obj file inside the objdir, while trying to link against a second obj file in the Makefile dir, this of course causes an error: `LINK : fatal error LNK1181: cannot open input file 'sort.obj'
Update: Solution proposed in the accepted answer works. Will leave the final version below.
# expands to root/bin/projname/bin
TARGET_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/bin
#expands to root/bin/projname/obj
OBJ_DIR := $(BINARY_DIR)/$(notdir $(patsubst %/,%,$(CURDIR)))/obj
# expands to a list of all the obj files created from the source files (a.obj, b.obj..)
OBJECTS := \
$(notdir $(patsubst %.cpp,%.obj,$(patsubst %.c,%.obj,$(SOURCES))))
SOURCES := $(wildcard src/*.c) $(wildcard src/*.cpp)
# default target
all: dirs $(TARGET).exe
# Link
$(TARGET).exe: $(addprefix $(OBJ_DIR)/,$(OBJECTS)))
$(LNK) $(LIB_PATH) $(LIBS) /OUT:$(TARGET_DIR)/$# $^
# Compile
$(OBJ_DIR)/$(OBJECTS): $(SOURCES)
$(CC) /c $(CFLAGS) $(INCLUDES) /Fo$(OBJ_DIR)/ /EHscT $(SOURCES)
.PHONY: build
dirs:
$(MKDIR) $(TARGET_DIR)
$(MKDIR) $(OBJ_DIR)
$(MKDIR) $(TEST_DIR)
This is not right:
$(OBJ_DIR)/$(OBJECTS)
What does this expand to? Let's say OBJECTS is foo.o bar.o baz.o and OBJDIR is obj. Then the above expands to:
obj/foo.o bar.o baz.o
which is clearly not what you want. If you want to prefix every word in a list with a value you can't just put the value before the entire list. You need to use something like:
$(addprefix $(OBJ_DIR)/,$(OBJECTS))
Related
Currently I am trying to get a rather big project of mine to work with a Makefile. I used Make before but in a rather crude way and not really "dynamic", this means I am pretty new to good Makefiles.
My Makefile looks like this:
INCLUDE_DIR = /inc
SOURCE_DIR = /src
BUILD_DIR = /build
BUILD_NAME = build
CC = arm-none-eabi-gcc
CFLAGS = -I$(INCLUDE_DIR)
_INCLUDES = main.h pfc.h
INCLUDES = $(patsubst %, $(INCLUDE_DIR)/%, $(_INCLUDES))
_OBJ = main.o pfc.o
OBJ = $(patsubst %, $(BUILD_DIR)/%, $(_OBJ))
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
all: $(BUILD_NAME)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)/*
When I make the file I get this:
make: *** No rule to make target '/build/main.o', needed by 'build'. Stop.
I guess it is an error in this recipe:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
Sadly I am not able to get this done on my own.
All files a available in the correct folders.
I really appreciate all the help!
Tristan
You have a few issues here that I can see. But first off - just check (just incase) that all your rules are only indented with tabs and not spaces..... this can be a real "silent" killer of makefiles as they give crap error messages.
Ok so - lets assume you have:
INCLUDE_DIR = inc
SOURCE_DIR = src
BUILD_DIR = build
instead of /src etc.. as mentioned in the comments.
Do you really have inc/main.h and inc/pfc.h?
I copied and pasted your makefile added your src and inc folders (but I used gcc instead of arm-none-eabi-gcc. It did the compile lines correctly, but failed at the linker stage because you are trying to build an output file called build when there is already a folder called build (not allowed in linux - maybe ok for windows but I don't recommend).
I made an answer for another question - but it might be a better start point then you have here in the case where you have nested src/inc directories and you want to be able to clean your output folders - ill put it here for convenience:
# Get your source list (use wildcard or what ever, but just for clarity you should end up with a list of files with full paths to start with):
# Output folders/targets
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
OUTPUT_FILE = output
# Generate list of source files - this is a linux command - but you can do this in pure make using wildcard and such).
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
# Create your objects list in the obj directory
OBJECTS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(SOURCES))))
# Create list of unique folders to create
DIRS = $(sort $(dir $(OBJECTS))) $(BIN_DIR)
# Create list of include paths
INCS = $(addprefix -I,$(sort $(dir $(SOURCES))))
# Main target rule
$(BIN_DIR)/$(OUTPUT_FILE): $(OBJECTS) | $(DIRS)
#echo linker: gcc $(OBJECTS) -o $#
#touch $#
# Rule to build your object file - ensure that the folders are created first (also create a dummy obj file) - note this works for parallel builds too (make -j
$(OBJ_DIR)/%.o: %.c | $(DIRS)
#echo compile: gcc $(INCS) -c $? -o $#
#touch $#
# Create your directories here
$(DIRS):
#echo Creating dir: $#
#mkdir -p $#
# Clean if needed
.PHONY: clean
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Note this is just a template, you still need to fill in the gcc/makefile flags - but its a decent start point...
Debugging
$(info ...) is your friend - for example you could do:
$(info OBJ = $(OBJ))
$(info objrule = $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES))
To print our what make has expanded these variables / lines to be - this can yield useful debug.
Here is another version of your makefile with automatic dependency generation:
INCLUDE_DIR := inc
SOURCE_DIR := src
BUILD_DIR := build
CC := arm-none-eabi-gcc
CPPFLAGS := -I$(INCLUDE_DIR)
exes := build
build.obj := main.o pfc.o
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CC} -o $# ${LDFLAGS} $^ ${LDLIBS}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : ${SOURCE_DIR}/%.c | $${#D}
${CC} -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
To add another executable target do:
exes += another
another.obj := another_main.o another_pfc.o
I have been editing this makefile but it's mostly trial and error.
Basically I have n .c files in the same directory. I want the first one (that has a fixed name) to be compiled and linked using my makefile hacks, that incorporate different .o files in the linking step, and all the other ones to be compiled and linked using only the LIBS (without the other .o files).
This is the 'main' makefile:
MAKEFILE_BASE = ./Build-Assets/Makefile
MAKEFILE_CONTROLLERS = ./Controllers/Makefile
.PHONY: default clean release release-clean
default: release
clean: release-clean
release:
$(MAKE) -f $(MAKEFILE_CONTROLLERS) # This generates the .o files, and it works well
$(MAKE) -f $(MAKEFILE_BASE).Release
release-clean:
$(MAKE) -f $(MAKEFILE_BASE).Release clean
And this is the 'Makefile.Release' that handles the compilation/linking of those .c files.
TARGET = $(notdir $(shell pwd))
LIBS = -lm -lev3dev-c -pthread
D_BIN = Build-Assets
ifeq ($(OS),Windows_NT)
LIBS := $(LIBS) -lws2_32
D_BIN := $(D_BIN)/mingw
endif
D_H = ../../source/ev3
CFLAGS = $(addprefix -I, $(D_H)) -O2 -std=gnu99 -W -Wall -Wno-comment
ifeq ($(OS),Windows_NT)
CC = gcc
else
CC = arm-linux-gnueabi-gcc
endif
ifeq ($(OS),Windows_NT)
E_BIN = .exe
else
E_BIN =
endif
F_BIN = $(TARGET)$(E_BIN)
OBJECTS = $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard *.c))) $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard Controllers/*.c)))
.PHONY: default all clean
default: $(F_BIN)
all: default
$(OBJECTS): $(D_BIN)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(F_BIN) $(OBJECTS)
$(F_BIN): $(OBJECTS)
$(info VAR is $#)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f $(D_BIN)/*.o
-rm -f $(F_BIN)
This also gives the output file the name of the main folder (though I don't understand where he does that?).
When linking this throws the 'multiple main' error (I don't have the ARM device at hand, so I can't provide the full error).
This is the folder hierarchy so that hopefully I can solve all your doubts..
# Main folder (This is the name that the compiled exe has)
## Controllers
-- .c & .h files
-- Makefile
## Build-Assets
-- all .o go here to clean up the folders
- Makefile (The one I call)
- main.c (this needs to be compiled with the .o in build-assets, name can be either main or main folder)
- gcheck.c (this needs to be compiled with only the LIBS, name of executable should be filename)
- ... other .c files, same as gcheck.c
Regarding "where the target name as the name of the directory" comes from, it's here:
TARGET = $(notdir $(shell pwd))
This runs the shell command pwd to get the full path of the current directory, then uses notdir to strip off the parent directory. Then the rule to link the executable uses this:
F_BIN = $(TARGET)$(E_BIN)
...
$(F_BIN): $(OBJECTS)
Regarding why you get multiple main errors, it's because you added your new .c file with the new main to the same directory and rather than the makefile listing a specific set of source files to compile and link, it uses wildcard to grab all the source files:
OBJECTS = $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard *.c))) $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard Controllers/*.c)))
These $(wildcard *.c) functions will expand to all the *.c files in these directories including any new ones you added. Then they will all be linked into the target, which gives you two different object files containing main.
You'll have to change this to list just the files you want, or put your files somewhere else, or remove your files from the list using make's filter-out function, or something like that.
I want to create a make file that takes all files in several src subdirectories and compiles them each directly into one single build directory.
I.e. i have e.g.
src/main.c
src/i2c/i2c.c
src/i2c/i2c.h
and as output i want the object files as well as the final binary
- build/main.o
- build/i2c.o
- build/release.elf
I manage to get all source files as a list with their respective subdirectory paths into a variable and I also manage to get a list of all output files but when i try to create a target to build all .o files in that build directory it does not match the corresponding .c files with the .o files. Here i am just not sure how to link these two.
It fails while trying to match main.o with i2c.c.
Here is "relevant" part of the Makefile:
TARGET = $(lastword $(subst /, ,$(CURDIR)))
BUILD_DIR := buildDir
SOURCES = $(wildcard src/*.c src/*/*.c)
BROKENOBJECTS = $(SOURCES:.c=.o)
LESSBROKEN = $(notdir $(BROKENOBJECTS))
OBJECT_FILES = $(addprefix $(BUILD_DIR)/, $(LESSBROKEN))
$(BUILD_DIR)/%.o: $(SOURCES) $(BUILD_DIR)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$(BUILD_DIR)/$(TARGET).elf: $(OBJECT_FILES)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $#
$(BUILD_DIR) :
mkdir -p $#
compile : $(BUILD_DIR)/$(TARGET).elf
How would I go about this, running the recipe for each .c file from $(SOURCES) and just create the corresponding .o file in buildDir/ ?
You could make use of make's vpath mechanism. So, rather than specifying possible source paths using...
SOURCES = $(wildcard src/*.c src/*/*.c)
you would have...
# Build a list of directories under src
#
SOURCE_DIRS := $(shell find src -type d)
# Use the list in $(SOURCE_DIRS) as a search path for .c files.
#
vpath %.c $(SOURCE_DIRS)
Now, when attempting to update i2c.o (for example), the rule...
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
will cause make to automatically search through the list of source directories for the dependency i2c.c.
Note: For obvious reasons multiple files with the same name under different source directories will cause problems here. Hence my original question (in the comments) regarding the uniqueness of source file names under different directories.
Assuming you use GNU make and your C source files are all *.c that can be found in the current directory and all its subdirectories (up to any depth), this should be close to what you want:
BUILDDIR := build
SRC := $(shell find . -type f -name '*.c')
# Convert C source file name(s) to object file name(s)
# $(1): C source file name(s)
define c2o
$(patsubst %.c,$(BUILDDIR)/%.o,$(notdir $(1)))
endef
OBJ := $(call c2o,$(SRC))
.PHONY: all
all: $(OBJ)
# Compilation rule for a C source file (use echo for testing)
# $(1): C source file name
define MY_rule
$$(call c2o,$(1)): $(1)
#echo $$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(TARGET_ARCH) -c -o $$# $$<
endef
# Instantiate compilation rules for all C source files
$(foreach s,$(SRC),$(eval $(call MY_rule,$(s))))
Demo:
host> tree .
.
├── Makefile
├── a.c
├── b
│ └── b.c
└── c
└── c
└── c.c
host> make
cc -c -o build/a.o a.c
cc -c -o build/c.o c/c/c.c
cc -c -o build/b.o b/b.c
Note the use of $$ in the definition of MY_rule. It is needed because it gets expanded twice: one time when expanding the parameters of the eval function and a second time when make parses the result as regular make syntax.
As explained in other comments and answers this works only if you don't have several C source files with the same base name. There is a way to detect this situation and issue an error if it is encountered. The make sort function sorts its word list parameter but it also removes duplicates. So, if the word count before and after sorting differ, you have duplicates. Add the following just after the definition of OBJ:
SOBJ := $(sort $(OBJ))
ifneq ($(words $(OBJ)),$(words $(SOBJ)))
$(error Found multiple C source files with same base name)
endif
Demo:
host> touch c/c/a.c
host> make
Makefile:13: *** Found multiple C source files with same base name. Stop.
Here is a modified snippet that should do what you want, though I didn't find a solution without specifying each subdirectory in src/ manually.
SOURCES = $(wildcard src/*.c)
SUBSOURCES = $(wildcard src/*/*.c)
OBJECTS = $(addprefix $(BUILD_DIR)/, $(notdir $(SOURCES:.c=.o)))
SUBOBJECTS = $(addprefix $(BUILD_DIR)/, $(notdir $(SUBSOURCES:.c=.o)))
compile : $(BUILD_DIR)/$(TARGET).elf
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) $(SUBOBJECTS)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $#
# save some typing for the rules below
COMPILE = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$(OBJECTS): $(BUILD_DIR)/%.o: src/%.c | $(BUILD_DIR)
$(COMPILE)
$(BUILD_DIR)/%.o: src/i2c/%.c | $(BUILD_DIR)
$(COMPILE)
$(BUILD_DIR)/%.o: src/someOtherSubdir/%.c | $(BUILD_DIR)
$(COMPILE)
As #G.M. suggested in the comments, you must make sure that source file names are unique across subdirectories. Note also that I turned $(BUILD_DIR) into an order only prerequisite, which should reflect your intention more precisely.
I have a Makefile that looks like this:
CC=cc
CFLAGS=-g -std=c99 -Wfatal-errors
OBJS=$(wildcard *.o)
all: main.o cmdargs.o io.o
$(CC) -o app $(OBJS)
main.o: main.c
$(CC) -c main.c $(CFLAGS)
cmdargs.o: cmdargs.c
$(CC) -c cmdargs.c $(CFLAGS)
io.o: io.c
$(CC) -c io.c $(CFLAGS)
clean:
#rm -rf app $(OBJS)
Whenever I run make all after a clean, there's an error saying
cc -o
undefined reference to `main'
But when I run it a second time everything works as expected. What is wrong with the script, and how can we fix it?
The previous respondents gave good answers but not complete. So let me post one too.
First of all, it is a bad idea to use wildcard in makefiles. It is much better to not be lazy and list your files explicitly.
If you must be lazy, the way to use wildcard is, as shawncorey writes, to use it for sources.
Also, do not have a recipe for phony targets such as all. In your example, the recipe for all will always run, which is inefficient.
CC := gcc
SRCS := $(wildcard *.c)
OBJS := $(SRCS:c=o)
.PHONY: all clean
all: app
app: $(OBJS) Makefile
$(CC) -o $# $(OBJS)
$(OBJS): %.o: %.c Makefile
$(CC) -c $< $(CFLAGS)
clean:
#rm -rf app $(OBJS)
You can automatically create the names of the objects files if you're careful about including all the source files.
# --------------------------------------
# list all source files
CPP_SOURCES := $(wildcard *.cpp)
C_SOURCES := $(wildcard *.c)
# other source files here
# consolidate all sources
SOURCES := $(CPP_SOURCES) $(C_SOURCES)
# --------------------------------------
# list all object files
CPP_OBJECTS := $(CPP_SOURCES:.cpp=.o)
C_OBJECTS := $(C_SOURCES:.c=.o)
# other object files here
# consolidate all objects
OBJECTS := $(CPP_OBJECTS) $(C_OBJECTS)
all:
echo $(SOURCES)
echo $(OBJECTS)
PS: A more compact makefile:
# list all source files
SOURCES := $(wildcard *.cpp) $(wildcard *.c)
# determine all object files
OBJECTS := $(addsuffix .o, $(basename $(notdir $(SOURCES))))
all:
echo $(SOURCES)
echo $(OBJECTS)
The statement
OBJS=$(wildcard *.o)
collects all the *.o files currently in the file system, but it doesn't know about any object files that might be created in the future.
When you run make for the first time, there are no .o files around, so the variable OBJS will be an empty string and the final linking command does not get passed into the command that would tell it which object files to use. But all the other compilation steps are run nevertheless. Upon the second invocation make will skip the compilation phases, because the object files are already there, but because linking failed and the final binary is missing, it will run that step, which will now produce something, because there have been files to collect by the wildcard.
Lesson learned: Don't use file system wildcards in Makefile, it's just causing trouble. Instead learn about implicit rules if you want to save yourself from work.
[edit]- The answer is I have incorrectly defined the path to the include directory. Embarrasing mistake.
I am writing a makefile that builds objects from .c files in a src directory with headers in an include directory and stores them in an obj directory, and then builds and exe from those objects. A toy version is below.
# Makefile
IDIR = ../include
CC = gcc
CFLAGS = -I$(IDIR) -Wall
SDIR = src
ODIR = obj
_SOURCES = main.c aux1.c aux2.c aux3.c
SOURCES = $(patsubst %,$(SDIR)/%,$(_SOURCES))
_OBJECTS = $(_SOURCES:.c=.o)
OBJECTS = $(patsubst %,$(ODIR)/%,$(_OBJECTS))
_DEPS = aux1.h aux2.h aux3.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
EXE = exefile
$(ODIR)/%.o: $(SDIR)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$(EXE): $(OBJECTS)
$(CC) -o $# $^ $(CFLAGS)
.PHONY: clean
clean:
rm *o $(EXE)
The directory the makefile is in looks like this (when you ls)
include Makefile obj src trash
When I type make, I get the following error
make: *** No rule to make target `obj/main.o', needed by `exefile'. Stop.
I suspect the problem is with this line
$(ODIR)/%.o: $(SDIR)/%.c $(DEPS)
I am attempting to build each object file in obj/ by referencing the corresponding source file in src/ but the line seems do to something else. Is this the case? Is there an easy way to reference .c files in the source directory without "entering" the directory?
Thanks in advance
I believe your problem is the $(DEPS) dependency.
You set IDIR to ../include but from the toplevel directory (where make is run from) that path is incorrect.