Makefile dependency rules for multiple source-object compilation - makefile

I apologize if this is a somewhat noobish question, I have been searching for a while and haven't found the answer.
I am new to makefiles, and am trying to create one which compiles multiple source files in various directories into object files in a single directory and then link them.
It works, but it always recompiles all the files even if I haven't changed them. To my understanding, it should only do this if the dependencies are older than the targets. What am I doing wrong?
Here is my makefile:
CC = mpic++
CCU = nvcc
ARCH = -arch=sm_52
SOURCEDIR = ./source
SOLVERDIR = $(SOURCEDIR)/solvers
OBJECTDIR = ./bin
INCLUDE = -I./include -I/home/alexander/.openmpi/include -I/usr/local/cuda-7.5/include
LIBRARY = -L/usr/local/cuda-7.5/lib64 -lcublas -lcudart
OUT = cgsolve
CDEPS = $(OBJECTDIR)/main.o $(OBJECTDIR)/timer.o $(OBJECTDIR)/cgMPIFuncs.o
compileC: $(CDEPS)
$(CC) $(INCLUDE) -c $(SOURCEDIR)/main.cpp -o $(OBJECTDIR)/main.o
$(CC) $(INCLUDE) -c $(SOURCEDIR)/timer.cpp -o $(OBJECTDIR)/timer.o
$(CC) $(INCLUDE) -c $(SOURCEDIR)/cgMPIFuncs.cpp -o $(OBJECTDIR)/cgMPIFuncs.o
CUDEPS = $(OBJECTDIR)/BiCGStab.o $(OBJECTDIR)/CG.o $(OBJECTDIR)/solverUtil.o $(OBJECTDIR)/cudaKernels.o
compileCU: $(CUDEPS)
$(CCU) $(ARCH) $(INCLUDE) -c $(SOLVERDIR)/BiCGStab.cu -o $(OBJECTDIR)/BiCGStab.o
$(CCU) $(ARCH) $(INCLUDE) -c $(SOLVERDIR)/CG.cu -o $(OBJECTDIR)/CG.o
$(CCU) $(ARCH) $(INCLUDE) -c $(SOURCEDIR)/solverUtil.cu -o $(OBJECTDIR)/solverUtil.o
$(CCU) $(ARCH) $(INCLUDE) -c $(SOURCEDIR)/cudaKernels.cu -o $(OBJECTDIR)/cudaKernels.o
OBJDEPS = $(OBJECTDIR)/main.o $(OBJECTDIR)/BiCGStab.o $(OBJECTDIR)/CG.o $(OBJECTDIR)/solverUtil.o $(OBJECTDIR)/cudaKernels.o $(OBJECTDIR)/timer.o $(OBJECTDIR)/cgMPIFuncs.o
build:
$(CC) $(OBJDEPS) $(LIBRARY) -o $(OUT)
all: compileC compileCU build
And again, sorry if this is a repeat or something. I haven't been able to find a previous version of this question. Thanks for the help!

Instead of setting rules explicitly altogether, please try pattern-rule like below, also it's better to add OBJDEPS as pre-requisite for build target (then no need for compileC and compileCU, unless you want to keep those targets)
compileC: $(CDEPS)
compileCU: $(CUDEPS)
build: $(OBJDEPS)
$(CC) $^ $(LIBRARY) -o $(OUT)
$(OBJECTDIR)/%.o : $(SOURCEDIR)/%.cpp
$(CC) $(INCLUDE) -c $^ -o $#
$(OBJECTDIR)/%.o : $(SOLVERDIR)/%.cu
$(CCU) $(ARCH) $(INCLUDE) -c $^ -o $#

Related

How to let avr-gcc output *.o to separate folder in Makefile with `%.o: %.c`?

As showed in first screenshot, my ideal AVR project structure is that:
*.o, *.elf and *.hex files are in build folder.
PomoScheler.c and pinDefines.h as main files are in root folder, while other *.c and *.h are in src folder.
But *.o are always generated at the same folder as *.c like showed in second screenshot, no matter how.
(I attached my endeavors and whole Makefile below the screenshots)
Firstly, I tried build/ before $#, in vain. The terminal still the same.
# My first Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$#
# Terminal command generated by Makefile (Look at the end: *.o path still same as *.c)
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -DF_CPU=1000000UL -DBAUD=9600UL -I. -I~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include -mmcu=atmega328p -c -o src/RotaryEncoder.o src/RotaryEncoder.c
Secondly, I tried to add mv $# build to explicitly move it to build folder. But nothing happened. Even echo are not displayed in Terminal.
# My second Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $#
mv $# build
echo ---------Hello---------
Thirdly, I delete $(HEADERS) and replace $< with $^ just to have a try. The mv is executed. But it cannot find *.o file this time even though I have VPATH = src:build in Makefile.
# My third Makefile endeavor
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $#
mv $# build
# Terminal error
Assembler messages:
Fatal error: can't create build/src/RotaryEncoder.o: No such file or directory
And my whole Makefile is here. Please help me out.
# My whole Makefile
MCU = atmega328p
F_CPU = 1000000UL
BAUD = 9600UL
LIBDIR = ~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include
PROGRAMMER_TYPE = usbtiny
PROGRAMMER_ARGS =
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
##########------------------------------------------------------##########
VPATH = ./src:./build
TARGET = $(lastword $(subst /, ,$(CURDIR)))
SOURCES=$(wildcard *.c src/*.c $(LIBDIR)/*.c)
OBJECTS=$(SOURCES:.c=.o)
HEADERS=$(SOURCES:.c=.h)
CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I. -I$(LIBDIR)
CFLAGS = -Os -g -std=gnu99 -Wall
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS = -Wl,-Map,build/$(TARGET).map
LDFLAGS += -Wl,--gc-sections
TARGET_ARCH = -mmcu=$(MCU)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$#
$(TARGET).elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o build/$#
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex build/$< build/$#
all: $(TARGET).hex
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
This is clearly not right:
OBJECTS = $(SOURCES:.c=.o)
because the object files you want to create are not foo.o etc. which is what this will expand to; the object files are build/foo.o etc. So this has to be:
OBJECTS = $(patsubst %.c,build/%.o)
All of your attempts to trick make by telling it your recipe will build one target (foo.o) but actually building a totally different target (build/foo.o) are doomed to fail, regardless of whether you have the compiler do it directly, you use mv, or any other method.
If you just tell make what your recipe actually does, you will have a much simpler time of it:
build/%.o: %.c
mkdir -p $(#D)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $#
Probably you have similar issues with the other rules that you want to put into other directories.
You can't do this by trying to hide it from make. Make has to know where the files actually are.
BTW, VPATH cannot help here. VPATH is for finding source files, it cannot be used for finding generated files. So you could use VPATH to find your .c files but not your .o files.

Why does my Makefile with pattern rules not create debugging symbols for main?

I am using this auto-generated Makefile with pattern rules, that I oviously do not understand yet. I want to create debuggins symbols and then debug main, but it doesn't work. There is a -g flag. Adding $(LDFLAGS) statement above after $(ODIR) does not print one as expcted.
IDIR =./include
CC=g++
CFLAGS = -I$(IDIR)
LDFLAGS = -g
ODIR=./
LIBS=
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
main: $(OBJ)
$(CC) $(LDFLAGS) -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o
This is the terminal output
g++ -c -o Source.o Source.cpp
g++ -g -o Source Source.o -I./include
Your sources are C++ (.cpp) but your Makefile contains explicit instructions for building C files. Make is therefore falling back to its built in implicit rules.
Also note that by convention those rules use $(CXX) to refer to the C++ compiler, with $(CXXFLAGS) replacing $(CFLAGS), and the -I flag belongs in $(CPPFLAGS):
IDIR =./include
CPPFLAGS = -I$(IDIR)
CXXFLAGS = -g
ODIR=.
LIBS=
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.cpp
$(CXX) -c -o $# $(CPPFLAGS) $(CXXFLAGS) $<
main: $(OBJ)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $# $^ $(LIBS)
.PHONY: clean
clean:
rm -f $(OBJ)
If you were to do away with the ODIR handling and use the conventional variable names you could do without the explicit .o: .cpp rule altogether.

How to build static library .a for ARM using cross compiler?

I was trying to compile statically cpp-netlib and rpclib for ARM device.(Same as ZEDboard)
Everything i did is changed the compiler and system settings in CMakeLists.txt file.
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_SYSROOT /home/a/buildroot-2018.05/output/host/arm-buildroot-linux-uclibcgnueabihf/sysroot/)
set(tools /home/a/buildroot-2018.05/output/host/bin/)
set(CMAKE_C_COMPILER ${tools}arm-buildroot-linux-uclibcgnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}arm-buildroot-linux-uclibcgnueabihf-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
After Makefile is created by cmake i ran make and no output has been produced. As i understand build directories should appear.
For the rpclib things went better. It has compiled the librpc.a file but unftunately its not linking to my program.
arm-buildroot-linux-uclibcgnueabihf-g++ -I/home/a/rpclib/include/ -Xlinker -static /home/a/rpclib/librpc.a main.cpp
produces this output:
/home/a/buildroot-2018.05/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/6.4.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: cannot find -lgcc_s
/home/a/buildroot-2018.05/output/host/lib/gcc/arm-buildroot-linux-uclibcgnueabihf/6.4.0/../../../../arm-buildroot-linux-uclibcgnueabihf/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
but there is gcc_s in the sysroot directory.
~/buildroot-2018.05/output/host/arm-buildroot-linux-uclibcgnueabihf$ find ./ -name *gcc_s*
./sysroot/lib/libgcc_s.so
./sysroot/lib/libgcc_s.so.1
./sysroot/usr/include/boost/asio/detail/gcc_sync_fenced_block.hpp
./sysroot/usr/include/boost/atomic/detail/caps_gcc_sync.hpp
./sysroot/usr/include/boost/atomic/detail/ops_gcc_sync.hpp
./sysroot/usr/include/boost/atomic/detail/ops_gcc_sparc.hpp
./sysroot/usr/include/boost/atomic/detail/caps_gcc_sparc.hpp
./sysroot/usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp
./lib/libgcc_s.so
./lib/libgcc_s.so.1
I guess i am missing something important about cross-compilation.
So basically i have 3 questions:
Can you suggest some resources about cross-compilation for embdedd devices?
How to compile cpp-netlib?
How to link already compiled librpc?
Actually buildroot supports building static libraries.
Steps to build a custom library using buildroot:
Create a folder inside buildroot/package folder with the name of target library.
e.g. my path looks like this /home/a/buildroot-2018.05/package/rpclib
Create Config.in file in target library dir with the needed parameters which can be checked in buildroot manual or better
Create [package-name].mk
Then add entry in /buildroot/package/Config.in
Then package can be marked for installation in menuconfig/target pacckages
My Config.in file for rpclib
config BR2_PACKAGE_RPCLIB
bool "rpclib"
depends on BR2_INSTALL_LIBSTDCPP
depends on BR2_USE_WCHAR
help
rpclib is a modern C++ msgpack-RPC server and client library
http://rpclib.net
My rpclib.mk file
RPCLIB_VERSION = v2.2.1
RPCLIB_SITE = $(call github,rpclib,rpclib,$(RPCLIB_VERSION))
RPCLIB_INSTALL_STAGING = YES
RPCLIB_INSTALL_TARGET = NO
RPCLIB_CONF_OPTS = -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF
$(eval $(cmake-package))
And entry in Config.in in the buildroot/packages dir
source "package/rpclib/Config.in"
After executing make i received
./output/host/arm-buildroot-linux-uclibcgnueabihf/sysroot/usr/lib/librpc.a
Working in my little beatle (https://gitlab.com/melviso1/beatle) I have a custom makefile for building rpclib without using cmake stuff (I apologize but I really hate cmake and similar tools). Maybe that can help.
Put it in the root of rpclib for building, clean or install. Please review tabs in the following script, because my pasting here can make some loses.
I used this to compile rpclib inside arm. For cross-compiling you could edit and change build tools.
CXXFLAGS=-std=c++0x -O3 -pthread -DASIO_STANDALONE -DRPCLIB_ASIO=clmdep_asio -DRPCLIB_FMT=clmdep_fmt -DRPCLIB_MSGPACK=clmdep_msgpack -Wall
INCLUDE=-Iinclude -I./dependencies/include
OBJS=obj/format.o obj/posix.o obj/client.o obj/client_error.o obj/response.o obj/server_session.o obj/dispatcher.o obj/optional.o obj/rpc_error.o obj/server.o obj/this_handler.o obj/this_server.o obj/this_session.o
all: obj librpc.a
obj:
mkdir -p obj
librpc.a: $(OBJS)
ar -r -s librpc.a $(OBJS)
obj/format.o: dependencies/src/format.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./dependencies/src/format.cc -o obj/format.o
obj/posix.o: dependencies/src/posix.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./dependencies/src/posix.cc -o obj/posix.o
obj/client.o: lib/rpc/client.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/client.cc -o obj/client.o
obj/client_error.o: lib/rpc/detail/client_error.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/detail/client_error.cc -o obj/client_error.o
obj/response.o: lib/rpc/detail/response.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/detail/response.cc -o obj/response.o
obj/server_session.o: lib/rpc/detail/server_session.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/detail/server_session.cc -o obj/server_session.o
obj/dispatcher.o: lib/rpc/dispatcher.cc
g++ $(CXXFLAGS) $(INCLUDE) -c ./lib/rpc/dispatcher.cc -o obj/dispatcher.o
obj/optional.o: lib/rpc/nonstd/optional.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/rpc_error.o: lib/rpc/rpc_error.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/server.o: lib/rpc/server.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/this_handler.o: ./lib/rpc/this_handler.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/this_server.o: lib/rpc/this_server.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
obj/this_session.o: ./lib/rpc/this_session.cc
g++ $(CXXFLAGS) $(INCLUDE) -c $< -o $#
install:
cp -rf include/rpc /usr/local/include/
cp librpc.a /usr/local/lib/
uninstall:
rm -rf /usr/local/include/rpc
rm /usr/local/lib/librpc.a
clean:
rm -f librpc.a
rm -f obj/*
.PHONY: obj clean install uninstall`

reduce the amount of duplicated rules in makefile

The goal is to specify a build directory where .o and the executable will reside after building the project
currently I've written this Makefile that does this but I have to specify for each object file its directory manually.
PROGNAME = parkingLotApp
CXX = g++
SRC = main.cpp \
parking_car.cpp \
parking_lot.cpp \
shader.cpp \
shader_manager.cpp
OBJS = main.o \
parking_car.o \
parking_lot.o \
shader.o \
shader_manager.o \
BUILDIR = build
CXXFLAGS = -Wall -c -std=c++11
LDFLAGS = -Wall
LIBS = -lGL -lGLEW -lglfw
$(PROGNAME): $(OBJS)
$(CXX) $(BUILDIR)/*.o $(LDFLAGS) $(LIBS) -o $(BUILDIR)/$(PROGNAME)
main.o:
$(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o
parking_car.o:
$(CXX) $(CXXFLAGS) $(INCDIR) parking_car.cpp -o $(BUILDIR)/parking_car.o
parking_lot.o:
$(CXX) $(CXXFLAGS) $(INCDIR) parking_lot.cpp -o $(BUILDIR)/parking_lot.o
shader.o:
$(CXX) $(CXXFLAGS) $(INCDIR) shader.cpp -o $(BUILDIR)/shader.o
shader_manager.o:
$(CXX) $(CXXFLAGS) $(INCDIR) shader_manager.cpp -o $(BUILDIR)/shader_manager.o
.PHONY: clean
clean:
rm $(BUILDIR)/*.o $(BUILDIR)/$(PROGNAME)
Again, this works as I expected but I want to get rid of manually specifying directory ($(BUILDIR)/someobject.o) for each .o file
I tried this instead of duplicated lines above
$(OBJS):
$(CXX) $(CXXFLAGS) $(INCDIR) $(SRC) -o $(patsubst %, $(BUILDIR)/%, $(OBJS))
but it gave an error for all build/*.o
saying that
no such file or directory
Why it does not work ?
Your attempt to combine all of the object file rules failed because the compiler did not know that you wanted to compile all of the source files separately.
We start with the object file rules:
main.o:
$(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o
...
Then we realize that these rules don't build what they claim to build; this rule claims to build main.o, but it actually builds build/main.o. This will cause trouble later, so we fix it:
$(BUILDIR)/main.o:
$(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o
...
Then we notice that we forgot to tell Make about the prerequisite source files-- Make does not know that it should rebuild this target if main.cpp has changed. So we correct that:
$(BUILDIR)/main.o: main.cpp
$(CXX) $(CXXFLAGS) $(INCDIR) main.cpp -o $(BUILDIR)/main.o
...
Then we use automatic variables to reduce the redundancy:
$(BUILDIR)/main.o: main.cpp
$(CXX) $(CXXFLAGS) $(INCDIR) $# -o $#
...
Then we notice that all of these object-file-building rules have exactly the same command, so we combine them into a pattern rule:
$(BUILDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) $(INCDIR) $# -o $#
(You could make them into a static pattern rule, but this is enough for one day.)
EDIT:
We must also change the PROGNAME rule to give it the correct name and prerequisites, and use automatic variables:
$(BUILDIR)/$(PROGNAME): $(addprefix $(BUILDIR)/, $(OBJS))
$(CXX) $^ $(LDFLAGS) $(LIBS) -o $#

gcc cannot specify -o with -c or -S with Multiple files

Whenever I am trying to build something like this in my Makefile -
gcc -o main.o -IStarterWare_Files -c main.c StarterWare_Files/test.h StarterWare_Files/add.h
It throws me error that gcc: cannot specify -o with -c or -S with multiple files. Basically I want my makefile to build the target again if I change for example some macro in one of my header files. My current Makefile is -
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CPPFLAGS = _IStarterWare_Files/
MAIN_OBS = $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS = $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $# $(LDFLAGS) $(MAIN_OBS) $(LIB_OBS) $(LDLIBS)
%.o: %.c
$(CC) -o $# -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
ALL_DEPS = $(patsubst %.o,%.d,$(MAIN_OBS), $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(LIB_OBS) $(EXE) $(MAIN_OBS) $(ALL_DEPS)
.PHONY: all clean
I can't figure out what changes to make to build my executable again if one of the header files is modified. I don't want to do make clean and make again.
The way the automake system handles this is to not use %.o: %.c but instead list the C file and all of the headers in the C file.
So for example:
main.o: main.c StarterWare_Files/test.h StarterWare_Files/add.h
$(CC) -o $# -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
See makedepends for a tool that will read C files and figure out the make dependencies.

Resources