Build individual .o files from .c files in Makefile - makefile

I'm trying to write a Makefile that will build a list of .o files from source, and then in a separate make target, setup linking etc. My Makefile currently looks like this:
CC=arm-none-eabi-gcc
vpath %.c src src/peripherals
vpath %.o out
OUT_DIR = out
CFLAGS = -DUSE_STDPERIPH_DRIVER
CFLAGS += -c -fmessage-length=0 -g3 -gdwarf-2 -O0 -Wall -Wa,-adhlns="$#.lst"
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -MMD -MP -MF"$#.d" -MT"$#.d"
CFLAGS += -Iinc -Iinc/cmsis -Iinc/peripherals -Iinc/stm32f4xx
SRC = misc.c stm32f4xx_adc.c stm32f4xx_can.c stm32f4xx_crc.c stm32f4xx_cryp.c stm32f4xx_cryp_aes.c \
stm32f4xx_cryp_des.c stm32f4xx_cryp_tdes.c stm32f4xx_dac.c stm32f4xx_dbgmcu.c stm32f4xx_dcmi.c stm32f4xx_dma.c \
stm32f4xx_exti.c stm32f4xx_flash.c stm32f4xx_fsmc.c stm32f4xx_gpio.c stm32f4xx_hash.c stm32f4xx_hash_md5.c \
stm32f4xx_hash_sha1.c stm32f4xx_i2c.c stm32f4xx_iwdg.c stm32f4xx_pwr.c stm32f4xx_rcc.c stm32f4xx_rng.c \
stm32f4xx_rtc.c stm32f4xx_sdio.c stm32f4xx_spi.c stm32f4xx_syscfg.c stm32f4xx_tim.c stm32f4xx_usart.c \
stm32f4xx_wwdg.c
OBJ = $(SRC:.c=.o)
%.o : %.c
$(CC) -c -o $# $< $(CFLAGS)
all: $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
I know this is terribly wrong, I'm not an expert with working in Makefile's, but I want to get this right, as it helps to understand the process a bit better.
What's basically required is to take the list of .c files in $(SRC) and build them into a list of .o files, which are output in lib/out
I know that my target and %.o... rule is horribly messed up. How do I get the all: target to build the individual .o files.
Here's the project structure just for reference, the Makefile I'm working on is in the ./lib folder.
.
├── Makefile
├── inc
│   └── main.h
├── lib
│   ├── Makefile
│   ├── inc
│   │   ├── cmsis
│   │   │   ├── arm_common_tables.h
│   │   │   ├── ...
│   │   ├── peripherals
│   │   │   ├── misc.h
│   │   │   ├── stm32f4xx_adc.h
│   │   │   ├── ...
│   │   └── stm32f4xx
│   │   ├── stm32f4xx.h
│   │   ├── stm32f4xx_conf.h
│   │   └── system_stm32f4xx.h
│   ├── src
│   │   └── peripherals
│   │   ├── misc.c
│   │   ├── stm32f4xx_adc.c
│   │   ├── ...
│   ├── startup_stm32f4xx.s
│   └── ~Makefile
├── readme.md
├── src
│   └── main.c
├── stm32f4.ld
├── stm32f4discovery.cfg
├── system_stm32f4xx.c
└── ~Makefile

typo OBJ = $(SRCS:.c=.o) change to OBJ = $(SRC:.c=.o), also looks like there is something messy with your dependency file generation.

Related

gcc does not read command line arguments from file

I am trying to build ZynAddSubFX using CMake, and it errored:
D:/work/zyn-fusion-build/src/zynaddsubfx/rtosc/src/rtosc.c:9:10: fatal error: rtosc/rtosc.h: No such file or directory
9 | #include <rtosc/rtosc.h>
| ^~~~~~~~~~~~~~~
compilation terminated.
This is the command (simplified):
gcc #CMakeFiles/rtosc.dir/includes_C.rsp -O2 -fPIC -std=c99 -Wall -Wextra -MD -MT rtosc/CMakeFiles/rtosc.dir/src/rtosc.c.obj -MF CMakeFiles/rtosc.dir/src/rtosc.c.obj.d -o CMakeFiles/rtosc.dir/src/rtosc.c.obj -c /g/Projects/zyn-fusion-build/src/zynaddsubfx/rtosc/src/rtosc.c
File system tree:
.
├── CMakeFiles
│   ├── CMakeDirectoryInformation.cmake
│   └── rtosc.dir
│      ├── DependInfo.cmake
│      ├── build.make
│      ├── cmake_clean.cmake
│      ├── cmake_clean_target.cmake
│      ├── compiler_depend.make
│      ├── compiler_depend.ts
│      ├── depend.make
│      ├── flags.make
│      ├── includes_C.rsp
│      ├── link.txt
│      ├── progress.make
│      └── src
├── CTestTestfile.cmake
├── Makefile
└── cmake_install.cmake
I can cat (command) CMakeFiles/rtosc.dir/includes_C.rsp, and if I replace #CMakeFiles/rtosc.dir/includes_C.rsp to the file's content, it will not make any error.
I can't edit Makefile directly because CMake will regenerate all Makefiles.
What should I do to solve this problem?
Edit 1:
CMakeLists.txt example:
add_library(rtosc src/rtosc.c src/dispatch.c src/rtosc-time.c)
target_include_directories(rtosc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
includes_C.rsp example:
-I"/g/Projects/zyn-fusion-build/src/zynaddsubfx/rtosc/include"
gcc --version:
$ gcc --version
gcc.exe (Rev4, Built by MSYS2 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

GCC Makefile Error : No rule to make target 'put.h', needed by 'straps.o'. Stop

I am trying to run my makefile using make run but its getting some errors : "No rule to make target 'put.h', needed by 'straps.o'. Stop". The error is about GCC can't find the headers file(put.h) when running makefile with the text below :
In kernel directory's Makefile
VPATH=../../include
all : straps.o entry.o head.o
straps.o : straps.c put.h
$(GCC) -c straps.c $(CFLAG)
entry.o : entry.S
$(GCC) -c entry.S $(CFLAG)
head.o : head.S
$(GCC) -c head.S $(CFLAG)
(straps.c include"put.h" so i need to include put.h)
I am trying to include headers file in the gcc command line (by using $(GCC) -c straps.c $(CFLAG) -I../include) but still not working. Can anyone explain why I am getting this error and suggest a fix solution if possible. Thank you
My file list
Linux
├── arch
│   └── riscv
│   ├── kernel
│   │   ├── entry.S
│   │   ├── head.S
│   │   ├── Makefile
│   │   ├── straps.c
│   │   └── vmlinux.lds
│   └── Makefile
├── include
│   ├── put.h
│   └── test.h
├── init
│   ├── main.c
│   ├── Makefile
│   └── test.c
├── lib
│   ├── Makefile
│   └── put.c
└── Makefile
Main Makefile gives the variable as below :
export
CROSS_= riscv64-unknown-elf-
AR=${CROSS_}ar
GCC=${CROSS_}gcc
LD=${CROSS_}ld
OBJCOPY=${CROSS_}objcopy
ISA ?= rv64imafd
ABI ?= lp64
INCLUDE = -I ../include
CF = -g -O3 -march=$(ISA) -mabi=$(ABI) -mcmodel=medany -ffunction-sections -fdata-sections -nostartfiles -nostdlib -nostdinc -static -lgcc -Wl,--nmagic -Wl,--gc-sections
CFLAG = ${CF} ${INCLUDE}
***Solution :
The kernel directory's Makefile Updated as below (refers to the answer given in the post below):
VPATH = ../../../include
CFLAG += -I../../../include
all : straps.o entry.o head.o
straps.o : straps.c put.h
$(GCC) -c straps.c $(CFLAG)
entry.o : entry.S
$(GCC) -c entry.S $(CFLAG)
head.o : head.S
$(GCC) -c head.S $(CFLAG)
I think that you're assuming that VPATH is somehow related to how the compiler locates header files. That is definitely not the case. VPATH is a make construct, and controls where make looks for prerequisites of targets appearing in the makefile.
It has absolutely nothing to do with where the compiler looks to find preprocessor include files. To control that you have to add -I options to the compile line.
So for example use:
VPATH = ../../../include
CFLAG += -I../../../include
The dependency list following "straps.o:" must refer to objects you have rules to actualy make within the makefile. In that makefile you have rules to make straps.o, entry.o, and head.o, but not put.h. Or straps.c for that matter.

go build does not compile local changes into main

I am relatively new to go, and I am having some trouble with the go build system.
GO Environment:
(base) ngadre-mbp:github.com ngadre$ go version
go version go1.14.5 darwin/amd64
(base) ngadre-mbp:github.com ngadre$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/ngadre/Library/Caches/go-build"
GOENV="/Users/ngadre/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/ngadre/Desktop/Workspace/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/5g/59l0__050lg6p4hv1wv7mhw40000gn/T/go-build110012391=/tmp/go-build -gno-record-gcc-switches -fno-common"
My directory structure is as below:
pwd: /Users/ngadre/Desktop/Workspace/go/src/github.com
.
├── coredhcp
│   ├── LICENSE
│   ├── README.md
│   ├── cmds
│   │   ├── client
│   │   ├── coredhcp
│   │   └── coredhcp-generator
│   ├── config
│   │   ├── config.go
│   │   ├── config_test.go
│   │   └── errors.go
│   ├── go.mod
│   ├── go.sum
│   ├── handler
│   │   └── handler.go
│   ├── logger
│   │   └── logger.go
│   ├── plugins
│   │   ├── dns
│   │   ├── example
│   │   ├── file
│   │   ├── leasetime
│   │   ├── nbp
│   │   ├── netmask
│   │   ├── plugin.go
│   │   ├── range
│   │   ├── router
│   │   └── serverid
│   └── server
│   ├── handle.go
│   └── serve.go
├── go-immutable-radix
│   ├── CHANGELOG.md
│   ├── LICENSE
│   ├── README.md
│   ├── edges.go
│   ├── go.mod
│   ├── go.sum
│   ├── iradix.go
│   ├── iradix_test.go
│   ├── iter.go
│   ├── node.go
│   └── raw_iter.go
Both the projects "coredhcp" and "go-immutable-radix" I have cloned using git clone
I did some changes to the "go-immutable-radix" project and added logs, however, I am not able
to build my local changes into the "coredhcp" project which uses this "go-immutable-radix" project.
go build cmds/coredhcp/main.go
Any suggestions how I can compile local changes in "A" project into "X" project through go build.
If you have a locally cloned version of another go module, use the replace directive in the go.mod (the go.mod for the coredhcp package) to point the local copy:
replace github.com/.../go-immutable-radix => ../go-immutable-radix

Xcode 7.3 + linking to relative paths = ld: file not found: ../lib/lib_.dylib

I have a project which compiles fine on Xcode 7.2 and earlier, but gets linker errors when compiling with Xcode 7.3. I've been able to narrow it down to a simple example project that duplicates the problem.
The basic project structure is like this:
.
├── one
│   ├── lib
│   │   └── lib1.dylib
│   └── src
│   └── one.c
├── two
│   ├── lib
│   │   └── lib2.dylib
│   └── src
│   └── three.c
└── three
├── lib
   │   └── lib3.dylib
└── src
└── two.c
lib3 links with lib2, and lib2 links with lib1. When the library is compiled, its output is in the ../lib directory relative to its src directory.
When I try to compile lib3, it errors with file not found: ../lib/lib1.dylib, even though ../../one/lib is in the library search path.
What strange and mystical linker flag can I use to get the search paths to work out okay? Or is this a bug with Xcode?
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C one/src
cc -I ../../include -c -o one.o one.c
cc -dynamiclib -undefined dynamic_lookup -flat_namespace -o ../lib/lib1.dylib one.o
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C two/src
cc -I ../../include -c -o two.o two.c
cc -dynamiclib -undefined dynamic_lookup -flat_namespace -L ../../one/lib -o ../lib/lib2.dylib two.o -l1
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C three/src
cc -I ../../include -c -o three.o three.c
cc -dynamiclib -undefined dynamic_lookup -flat_namespace -L ../../two/lib -L ../../one/lib -o ../lib/lib3.dylib three.o -l2
ld: file not found: ../lib/lib1.dylib for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [../lib/lib3.dylib] Error 1
make: *** [all] Error 2
OK it took me a while to fix this error. I knew that part of the issue was setting the runpath and the install name of the libraries, so they could be found during linking and at runtime, which would be the next issue you faced.
I settled for building the libraries into a common top-level lib directory, however at the end of the day I'm pretty sure that actually wasn't necessary, but it did cut down on command line options being passed to the linker which is very cumbersome as it needs to be done with -Wl,-linker-option and -Wl,linker-option-argument as you are using cc for linking rather than ld directly.
I think the actual answer is to add -l1 to your three/src/Makefile line:
$(LD) -o $# $< -l2 -l1
It's not clear to me why this was necessary as if lib3 depends on lib2 then it shouldn't be necessary to add lib2's dependencies into the linker line. It's perhaps something to do with your use of -undefined dynamic_lookup, as I've never seen that option used before. However I didn't have time to experiment fully with this.
If you make this change to your version of the Makefiles you will likely have runtime issues as the runpath and install name are implied from whatever you passed to -L (which was ../../one/lib and ../../two/lib and they will almost certainly be wrong at runtime). Therefore it's better to explicitly set the runpath and install name, and every library had their runpath set to #loader_path/ and their install name set to #rpath/libX.dylib. The executable that uses these libraries will likely want a different runpath in order to find the libraries.
See my pull request for the changes I made.
I would like to commend you on how you presented this question with a testable project hosted on github; without that you would be unlikely to get any decent feedback.

Makefile vpath %.o not finding obj files

I'm using the following vpath to attempt locating my $(OBJ) files:
vpath %.o ./lib/obj
And my target is setup as such:
# Link target
link:
#echo "\nLinking files"
$(CC) $(LINK_FLAGS) -o main.elf $(OBJS)
When looking at the output, I get (for all the *.o files):
...error: misc.o: No such file or directory
My project structure looks as follows:
.
├── Makefile
├── inc
│   └── main.h
├── lib
│   ├── inc
│   │   ├── cmsis
│   │   │   ├── arm_common_tables.h
│   │   │   ├── ...
│   │   ├── peripherals
│   │   │   ├── misc.h
│   │   │   ├── ...
│   │   └── stm32f4xx
│   │   ├── stm32f4xx.h
│   │   ├── ...
│   ├── obj
│   │  ├── misc.o
│   ├── src
│   │   ├── peripherals
│   │   │   ├── misc.c
│   │   │   ├── ...
│   │   └── system_stm32f4xx.c
│   └── startup_stm32f4xx.s
├── src
│   └── main.c
└── stm32f4.ld
Why are my .o files not being found?
Full output for reference:
arm-none-eabi-gcc -T"stm32f3.ld" -nostartfiles -Wl,-Map,"main.map"
-mcpu=cortex-m4 -mthumb -g3 -gdwarf-2 -L"./" -o main.elf misc.o stm32f4xx_adc.o stm32f4xx_can.o stm32f4xx_crc.o stm32f4xx_cryp.o
stm32f4xx_cryp_aes.o stm32f4xx_cryp_des.o stm32f4xx_cryp_tdes.o
stm32f4xx_dac.o stm32f4xx_dbgmcu.o stm32f4xx_dcmi.o stm32f4xx_dma.o
stm32f4xx_exti.o stm32f4xx_flash.o stm32f4xx_fsmc.o stm32f4xx_gpio.o
stm32f4xx_hash.o stm32f4xx_hash_md5.o stm32f4xx_hash_sha1.o
stm32f4xx_i2c.o stm32f4xx_iwdg.o stm32f4xx_pwr.o stm32f4xx_rcc.o
stm32f4xx_rng.o stm32f4xx_rtc.o stm32f4xx_sdio.o stm32f4xx_spi.o
stm32f4xx_syscfg.o stm32f4xx_tim.o stm32f4xx_usart.o stm32f4xx_wwdg.o
system_stm32f4xx.o
$(OBJS) is just a variable, and gets expanded as text. When it appears in the text of the command in your link rule, it is simply expanded as text.
vpath searches are applied to prerequisites, so you will have to arrange for your $(OBJS) to appear as prerequisites to your link rule and for the rule's commands to use those prerequisites (via automatic variables, rather than just using $(OBJS) directly).
So your rule needs to look more like
# Link target
link: main.elf
main.elf: $(OBJS)
#echo "\nLinking files"
$(CC) $(LINK_FLAGS) -o $# $+
(I have also taken the liberty of writing out the file generated (main.elf) as the non-phony target of an intermediate rule. Making these things explicit to Make is generally a good idea.)
Although the other answers are correct in the details of what they say, there is a larger point here: it is not possible to use VPATH/vpath reliably to find derived files, like .o files that you build from your makefile. VPATH/vpath is only useful for finding source files, such as .c files.
You should read http://make.mad-scientist.net/vpath.html
vpath just tells make where to find the files, not the compiler/linker. You have to get make to tell the compiler/linker where it found them. The easiest way is to make them proper dependencies (so they get rebuilt before linking) and then use $^:
# Link target
link: $(OBJS)
#echo "\nLinking files"
$(CC) $(LINK_FLAGS) -o main.elf $^
I've added the following to my Makefile:
OBJS = $(LIB_SRC:.c=.o)
OBJ_FILES = $(addprefix lib/out/,$(notdir $(LIB_SRC:.c=.o)))
and updated the target:
link:
#echo "\nLinking files"
$(CC) $(LINK_FLAGS) -o main.elf $(OBJ_FILES)
The linker is now finding the .o files correctly.

Resources