How to add headers to a Makefile? - c

I have the following Makefile. How to add also some header files that I have in the project folder (e.g. header1.h with its relative header1.c) ?
CC := gcc
CFLAGS := -Wall -Wextra -Wpedantic -O3
CFILES := $(shell ls *.c)
PROGS := $(CFILES:%.c=%)
all: $(PROGS)
.PHONY: all clean
clean:
rm -f *~ $(PROGS)
Even adding them one by one would be ok (no need to use the wildcard).
I suppose I should edit the following line:
CFILES := $(shell ls *.c)
But how?

First, don't use $(shell ls *.c) but better $(wildcard *.c). Please take time to read the documentation of GNU make
Then, you usually don't want headers in Makefile-s, you want dependencies on headers.
For example, if you know that foo.o needs both foo.c and header.h (because you have some #include "header.h" in your foo.c) you would add a dependency like
foo.o: foo.c header.h
in your Makefile... See also this example.
There is some way to automate such dependencies, using GCC options; read about Invoking GCC, notably preprocessor options like -M
(details depend upon your project and coding conventions)
For a simple project of a few dozen of files totalizing a few thousand lines, you should first write your Makefile explicitly, with the dependencies. Later you might automatize that (but in simple projects that is not worth the trouble).
In some cases, a header file *.h or a C file *.c is generated by some utility (e.g. swig, bison, ... or your own script or program). Then you add appropriate specific rules in your Makefile.
You might use make --trace or remake with -x to debug your Makefile.
Look for inspiration into the source code of some existing free software project (e.g. on github).

Related

Problems with inclusion of C header file with automatically generated makefile

I have started to develop the C language software in the Xilinx Vitis IDE which Eclipse based. Organization of my project is following:
-Application
-Drivers
-drivers
-Adc
-Pwm
-Pwm.c
-Pwm.h
-Utils
-Bits.h
-Maths.h
All the directories i.e. Application, Drivers and Utils are linked into the workspace via "Link folder" option. The only one way how I was able to include the Bits.h into the Pwm.c was to specify the whole path to the Bits.h on my disk. Otherwise the compiler reports fatal error: Bits.h: No such file or directory.
The compilation process is managed by the automatically generated makefile with this content:
# Makefile generated by Xilinx.
PROCESSOR = ps7_cortexa9_0
LIBRARIES = ${PROCESSOR}/lib/libxil.a
BSP_MAKEFILES := $(wildcard $(PROCESSOR)/libsrc/*/src/Makefile)
SUBDIRS := $(patsubst %/Makefile, %, $(BSP_MAKEFILES))
ifneq (,$(findstring win,$(RDI_PLATFORM)))
SHELL = CMD
endif
all: libs
#echo 'Finished building libraries'
include: $(addsuffix /make.include,$(SUBDIRS))
libs: $(addsuffix /make.libs,$(SUBDIRS))
clean: $(addsuffix /make.clean,$(SUBDIRS))
$(PROCESSOR)/lib/libxil.a: $(PROCESSOR)/lib/libxil_init.a
cp -f $< $#
%/make.include: $(if $(wildcard $(PROCESSOR)/lib/libxil_init.a),$(PROCESSOR)/lib/libxil.a,)
#echo "Running Make include in $(subst /make.include,,$#)"
$(MAKE) -C $(subst /make.include,,$#) -s include "SHELL=$(SHELL)" "COMPILER=arm-none-eabi-gcc" "ASSEMBLER=arm-none-eabi-as" "ARCHIVER=arm-none-eabi-ar" "COMPILER_FLAGS= -O2 -c" "EXTRA_COMPILER_FLAGS=-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -nostartfiles -g -Wall -Wextra -g3 -O0"
%/make.libs: include
#echo "Running Make libs in $(subst /make.libs,,$#)"
$(MAKE) -C $(subst /make.libs,,$#) -s libs "SHELL=$(SHELL)" "COMPILER=arm-none-eabi-gcc" "ASSEMBLER=arm-none-eabi-as" "ARCHIVER=arm-none-eabi-ar" "COMPILER_FLAGS= -O2 -c" "EXTRA_COMPILER_FLAGS=-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -nostartfiles -g -Wall -Wextra -g3 -O0"
%/make.clean:
$(MAKE) -C $(subst /make.clean,,$#) -s clean
clean:
rm -f ${PROCESSOR}/lib/libxil.a
It is obvious that my "solution" is unacceptable. So I would like to ask you for an advice how to resolve this issue correctly. Thanks in advance for any suggestions.
You can add include paths to the project. These are paths where the compiler will search for include files. Any include file located in one of the directories in the include paths list should be found; you do not need to specify its path when including the file.
How you do this in the Xilinx environment appears to depend on how your project is set up.
If it is a managed make project:
Properties -> C/C++ Build
In "Tools Settings" tab select the "Include Paths"
If it is a standard make project:
Properties->C/C++ Include Paths and Symbols>
Then "Add External Include Path"
If it gives you the option to add the path as absolute or relative path, choose relative path; this allows another user to put the project, with the same internal directory structure, in a different place on the hard drive, which is what you want. In the screenshots in the documentation I referenced, the paths appear relative.
See this documentation for more details, screenshots, etc.
Note: I am answering based on the documentation; I have not worked with this IDE myself.
Note also that you can use relative paths in an #include directive, but they are not necessarily relative to the location of the file that includes them. They are more likely to be relevant to the root of the project (basically, wherever 'make' will be effectively run).

Referencing a C code-defined macro within its makefile

I'm writing some embedded firmware using C with arm-gcc and Eclipse.
Within my code is a FW version number defined as a macro.
I want to have that version appended to the build target file automatically.
For the sake of the example, let's say this is my main.h file:
#ifndef MAIN_H__
#define MAIN_H__
#define FW_MAJOR_VERSION 1
#define FW_MINOR_VERSION 0
and the makefile:
TARGET := fw_release
OUTPUT_DIR := out
...
generate_pkg:
#gen_pkg $(OUTPUT_DIR)/$(TARGET)_pkg.zip
where gen_pkg is some script to generate a firmware update package.
This would generate a file path like this: out/fw_release_pkg.zip
Ideally, I would like something like this:
generate_pkg:
#gen_pkg $(OUTPUT_DIR)/$(TARGET)_pkg_v$(FW_MAJOR_VERSION).$(FW_MINOR_VERSION).zip
which would generate a file path like this: out/fw_release_pkg_v1.0.zip
Now I know I can define the version within the makefile and reference that within the code (basically the other way around), but that has 2 problems:
Every time I change the makefile it triggers a compilation of the entire code which takes a few minutes.
I have two separate build configurations (release and debug), each using its own makefile, and that would require me to update the two separately.
The approach I'd take would be to define the version number elements in the Makefile, and burn those in to your code using cflags.
In the Makefile:
FW_VERSION_MAJOR=1
FW_VERSION_MINOR=1
FW_VERSION_MICRO=0a
FW_VERSION = $(FW_VERSION_MAJOR).$(FW_VERSION_MINOR).$(FW_VERSION_MICRO)
CFLAGS += -DFW_VERSION_MAJOR=$(FW_VERSION_MAJOR)
CFLAGS += -DFW_VERSION_MINOR=$(FW_VERSION_MINOR)
CFLAGS += -DFW_VERSION_MICRO=$(FW_VERSION_MICRO)
debug_build:
$(CC) -DDEBUG=1 $(OBJECTS) -o $(OUTPUT)
release_build:
$(CC) -DDEBUG=0 $(OBJECTS) -o $(OUTPUT)
Then it's a fairly easy matter to burn the correct version into your debug and
non-debug pkg generation - and you only have to change the firmware version info
in one place.
Well, you'll have to parse main.h one way or another.
Assuming that you're using gcc or clang:
generate_pkg: main.h
#gen_pkg "$(OUTPUT_DIR)/$$(echo FW_MAJOR_VERSION/FW_MINOR_VERSION | $(CC) -P -E -include main.h -x c -)_pkg.zip"
If your main.h is more complicated than that, you'll have to add all your $(CFLAGS) and other default options to the $(CC) command.

How to modify makefile to compile changed source into object directory except for a list of files

I inherited a makefile that uses GNU Make 3.81. It is overly complicated, IMHO because it does not use patterns. In addition, it does not automatically create an object file directory when needed. I've looked at several examples and read the a GNU makefile manual, but still not seeing something that should be simple. There seem to be many ways recommended, but not clear what to use. I have about 60 c files that need to be compiled into a directory named obj. But, I don't want 6 test programs that have 'main' programs compiled into that directory. They are in a list called OTHERSRCS. I'd like to have the c files less the OTHERSRCS compiled into obj if anything changes in those files. Also, if the obj directory doesn't exist, I'd like to create it. The 'make clean' should remove that directory. I've used ANT with Java and can get the dependencies to work, but I'm not succeeding with this makefile. A simple example would be helpful that used some sort of exclusion along with the pattern for the c files.
In this simple example, the C source files in the current directory
are foo.c, bar.c, atest.c, anothertest.c. We have:
OTHERSRCS := atest.c anothertest.c
Each of the $(OTHERSRCS) is to be separatedly compiled and linked into
a program in current directory. All remaining C source files, whatever
the are, are to be compiled into a directory obj, which shall be
created when required, and the resulting object files all linked into
a program foobar.
Makefile
ALLSRCS := $(wildcard *.c)
OTHERSRCS := atest.c anothertest.c
foobar_SRCS := $(filter-out $(OTHERSRCS),$(ALLSRCS))
foobar_OBJS := $(addprefix obj/,$(foobar_SRCS:.c=.o))
PROGS := foobar atest anothertest
.PHONY: all clean
all : $(PROGS)
obj/%.o: %.c | obj
$(COMPILE.c) $< -o $#
obj:
mkdir -p $#
foobar: $(foobar_OBJS)
$(LINK.o) -o $# $^ $(LDLIBS)
clean:
rm -fr $(PROGS) obj
The default make runs like:
$ make
mkdir -p obj
cc -c foobar.c -o obj/foobar.o
cc -c foo.c -o obj/foo.o
cc -c bar.c -o obj/bar.o
cc -o foobar obj/foobar.o obj/foo.o obj/bar.o
cc atest.c -o atest
cc anothertest.c -o anothertest
and of course make foobar like the first 5 lines of that.
To understand the key details, see 4.3 Types of Prerequisites
and 8.2 Functions for String Substitution and Analysis
in the manual. No recipes need be written for the programs atest and anothertest in this example because they're correctly built by GNU make's default rules.
If you are going to rework your inherited makefile, consider rationalising the source tree, e.g. by at least not having test sources in the same directory as application sources.
Here's my Makefile
This should get you going. I tried to be as descriptive as I could.
Edit:
To exclude a .c file you can change:
SRC = $(shell find $(SRC_DIR) -name '*.c')
to
SRC = $(shell find $(SRC_DIR) -name '*.c' ! -iname 'myFile.c')

C Makefile to compile some selective files

I am working on a C project which contains around 200 .c files and some .h files. Not all of these 200 files are required in the final product. Currently around 180 files needs to be compiled. We have a file "compile_only_these.c" which includes these 180 *.c files required for the project. Our makefile compiles only this file instead of individual .c files.
/* file: compile_only_these.c*/
#include "file1.c"
#include "file2.c"
.
.
.
#include "file180.c"
But I think including .c files is a bad idea. Because every time I modify any of these files, all files are compiled again.
Can you suggest a better way to compile these files.
More info:
All .c files are in same folder "../project/src"
I keep adding new .c files which are required to be compiled. I dont want to modify Makefile every-time I add a new file.
I still want to keep those 20 .c files which I am not compiling right now. I may use it in future. Deleting these files are moving them to other directory is not a solution
What you need is a variable in the makefile, a list of required object files, like this:
OBJS := file1.o file2.o ... file180.o
You can have Make construct it from the compile_only_these.c file like this:
OBJS := $(shell sed -e '/\#include/!d' -e 's/\#include "\(.*\)\.c"/\1.o/' compile_only_these.c)
Do you also need a hand with the rule that uses these objects to construct the final product?
As already mentioned, it's sort of a weird way to manage a project, but given what you have to work with, you might try something along this approach...
CC = gcc
OBJFILE = myprog
# Tweak to match whatever you compile with normally
CFLAGS = -O2 -Wall -std=c89 -pedantic
LDFLAGS= # Extra flags here, for example -lm -pthread
RM = rm -f
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
$(OBJFILE):$(OBJS)
$(CC) -o $# $^ $(LDFLAGS)
clean:
$(RM) core *~ $(OBJS) $(OBJFILE)
You will obviously need to adjust the path(s) for the specifics of your build hierarchy if you want to do more in your make than just compile this list of files, but this is a general approach for grabbing all files with wildcard substitution.

Why does this makefile not apply includes to all objects?

This makefile does not behave as I expect. I want it to build .o files for each .c file in the current directory and subdirectories, and put them in a static library. However, it stops applying my $(INCS) after the first or second file. When it tries to build the second .o file, I don't see the -I paths in the build line and it complains about not finding a header file therein. Names have been genericized to simplify things. I'm using cygwin on Windows XP. I'm using an ARM cross compiler that is not under the cygwin tree. I based this makefile off an answer here. There are only about two dozen .c files so the overhead of creating the dependency files this way isn't a big deal.
# Project specific options
CC = my-cross-gcc
INCS := -I. -Iinc
INCS += -Imy/inc/path
CFLAGS := -Wall -fPIC -static -cross-compiler-specific-options
OUT := bin/libmylib.a
MKDIR:=mkdir -p
### Generic C makefile items below:
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
NODEPS:=clean
#Find all the C files in this directory, recursively
SOURCES:=$(shell find . -name "*.c")
#These are the dependency files
DEPFILES:=$(patsubst %.c,%.d,$(SOURCES))
OBJS:= $(patsubst %.c,%.o,$(SOURCES))
#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
-include $(DEPFILES)
endif
#This is the rule for creating the dependency files
%.d: %.c
$(CC) $(INCS) $(CFLAGS) -MM -MT '$(patsubst %.c, %.o,$(patsubst %.c,%.o,$<))' $< > $#
#This rule does the compilation
%.o: %.c %.d %.h
$(CC) $(INCS) $(CFLAGS) -o $# -c $<
# Now create a static library
all: $(OBJS)
#$(MKDIR) bin
ar rcsvq $(OUT) $(OBJS)
clean:
rm -rf $(OBJS) $(OUT) $(DEPFILES)
Why does this makefile not apply $(INCS) when building subsequent .o files? How do I fix it? Output resembles this:
$ make all
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o firstfile.o -c firstfile.c
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o secondfile.o -c secondfile.c
my-cross-gcc -<compiler flags> -o thirdfile.o -c thirdfile.c
thirdfile.c:23:18: fatal error: myinc.h: No such file or directory
compilation terminated.
When I go to the command line and type in the gcc line to build thirdfile.o and use the -I paths, the object file is successfully built.
There are two different mechanisms for handling header files at work here:
When the compiler is trying to build foo.o from foo.c, and in foo.c it encounters #include "foo.h", it goes looking for foo.h. The -I flags tell it where to look. If it is invoked without the flags it needs to find foo.h, it will complain and die.
When Make is trying to build foo.o, and considering which rule to use, it looks at the prerequisites. The prerequisites for your rule are foo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know where foo.h is? Note that the compiler flag inside one of its commands is of no use-- it won't make any deductions about that. If it can't find (and doesn't know how to make) a prerequisite, it will reject that rule and look for another one, such as the implicit %.o rule which knows nothing about your $(INCS) variable, and that leads you to the problem described above.
If this is the problem (and you can check by looking at the locations of the headers and doing some experiments) you have a couple of options:
A) You can use the implicit rule, and it's variables. Just add INCS to CFLAGS and you'll probably get the results you want. This tells the compiler what to do, but it still leaves Make in the dark about the dependencies, so you'll probably have to double-check that your dependency handling is correct.
B) You can tell Make where to find the header files:
vpath %.h inc my/inc/path
(You may notice that this is redundant with your INCS variable, and redundancy is bad-- you can eliminate this redundancy, but I urge you to get it working first.)
I'm going to guess that you have files named firstfile.h, secondfile.h, but no file named thirdfile.h?
I would then suppose that make cannot use the rule you gave it because and can't find or build the .h file. So it decides to use the default implicit rule instead.
All I can imagine is that for "thirdfile" your depfile is somehow out-of-date or corrupt. Perhaps it is bad enough that it's confusing make into calling some other default target.

Resources