Makefile recursive not passing CPPFLAGS - c

First of all, sorry if I end up making a too long post, but I think it would be missing information otherwise.
I'd like to include my repository version in each build.
There is a main makefile that masters some other ones in their respective subdirectories.
The subprojects are "automaked".
I am trying to pass a variable containing the svnversion to inner Makefiles like this:
# Main Makefile
SUBDIRS = sd1 sd2
REPO_VERSION = `svnversion`
export ECHO = #echo
export CPPFLAGS
all: versioned
$(ECHO) "Build of all projects in $(PWD) finished."
clean :
$(ECHO) "Cleaning up entire project tree..."
-for d in $(SUBDIRS); do ($(ECHO) "Cleaning up \"$$d\""; $(MAKE) -C $$d clean ); done
.PHONY: versioned unversioned $(SUBDIRS)
versioned: CPPFLAGS = -DREPO_VERSION=\"v$(REPO_VERSION)\"
versioned: subdirs
unversioned: subdirs
versioned unversioned:
$(ECHO) "Build $# finished."
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(ECHO) "== Building $# =="
$(ECHO) " [ CPPFLAGS = \"$(CPPFLAGS)\" ]"
( cd $# && \
( [ -f Makefile ] || \
( aclocal && \
autoheader && \
automake --foreign --add-missing && \
autoconf && \
configure ) ) && \
$(MAKE) \
)
Each subdirectory has a Makefile.am and configure.ac like this:
Makefile.am:
# Makefile.am in "sd1" and "sd2"
bin_PROGRAMS = app
app_SOURCES = source.c
configure.ac:
AC_PREREQ(2.59)
AC_INIT([app], [1.00], [<suport#domain>])
AM_INIT_AUTOMAKE
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_CPP
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
# Checks for header files.
AC_HEADER_STDC
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
# Output configuration files.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
I expected this to work, but autotools are embedding REPO_VERSION in the makefile when run, and changes in the main Makefile's REPO_VERSION are ignored in further builds.
A piece of an output looks like this:
== Building sd1 ==
[ CPPFLAGS = "-DREPO_VERSION="1050"" ]
( cd sd1 && \
( [ -f Makefile ] || \
( aclocal && \
autoheader && \
automake --foreign --add-missing && \
autoconf && \
configure ) ) && \
make \
)
make[1]: Entrando no diretório `./recursive/sd1'
make all-am
make[2]: Entrando no diretório `./recursive/sd1'
gcc -DHAVE_CONFIG_H -I. -DREPO_VERSION=\"1049M\" -g -O2 -MT source.o -MD -MP -MF .deps/source.Tpo -c -o source.o source.c
mv -f .deps/source.Tpo .deps/source.Po
gcc -g -O2 -o app source.o
make[2]: Saindo do diretório `./recursive/sd1'
make[1]: Saindo do diretório `./recursive/sd1'
The program outputs:
> ./sd1/appVersão = [1049M].
This clearly is not what I wanted.
Can anybody here please give a way to fix this?
Thanks.

In your top level make file add
export REPO_VERSION
and modify each Makefile.am to have
REPO_VERSION ?= unknown
AM_CPPFLAGS = -DREPO_VERSION="$(REPO_VERSION)"
The export directive makes it so that the value of REPO_VERSION is exported to recursive make invocations. The Makefile.am snippet sets a default value for REPO_VERSION if it is not given (e.g. make is run from the shell in the subdirectory) and AM_CPPFLAGS specifies the default value of CPPFLAGS for all targets in that Makefile. If you have a target specific _CPPFLAGS variable, you should either add $(AM_CPPFLAGS) to that or include the -DREPO_VERSION="$(REPO_VERSION)" in it. With a bit more effort you can add some stuff into the configure.ac files so that the default for REPO_VERSION can be set at configure time.

You are trying to pass CPPFLAGS via the environment, but I don't see where the invocation of configure is getting CPPFLAGS set in its environment. Try passing it at the command line:
$(SUBDIRS):
$(ECHO) "== Building $# =="
$(ECHO) " [ CPPFLAGS = \"$(CPPFLAGS)\" ]"
cd $# && autoreconf -i && ./configure CPPFLAGS=$(CPPFLAGS) && $(MAKE)
Also, you are only running configure once. After the Makefile exists, you do not rerun configure, so you never reset the value of CPPFLAGS in the subdirectory.
Setting the version at configure time is very inconvenient. Take a look here for some techinques that allow the version to be set at make time.

Related

Convert micropython makefile to cmakelist.txt

I am trying to convert micropython makefile to cmakelists.txt from https://docs.micropython.org/en/latest/develop/porting.html
# Include the core environment definitions; this will set $(TOP).
include ../../py/mkenv.mk
# Include py core make definitions.
include $(TOP)/py/py.mk
# Set CFLAGS and libraries.
CFLAGS = -I. -I$(BUILD) -I$(TOP)
LIBS = -lm
CROSS_COMPILE ?= arm-none-eabi-
# Define the required source files.
SRC_C = \
main.c \
mphalport.c \
lib/mp-readline/readline.c \
lib/utils/gchelper_generic.c \
lib/utils/pyexec.c \
lib/utils/stdout_helpers.c \
# Define the required object files.
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
# Define the top-level target, the main firmware.
all: $(BUILD)/firmware.elf
# Define how to build the firmware.
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $#"
$(Q)$(CC) $(LDFLAGS) -o $# $^ $(LIBS)
$(Q)$(SIZE) $#
# Include remaining core make rules.
include $(TOP)/py/mkrules.mk
Current progress on cmakelists.txt
cmake_minimum_required(VERSION 3.17)
set(CMAKE_CXX_STANDARD 14)
set(MICROPY_TARGET firmware)
set(MICROPY_DIR "../..")
set(MICROPY_PORT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
include(${MICROPY_DIR}/py/py.cmake)
project(${MICROPY_TARGET})
set(MICROPY_SOURCE_PORT
${MICROPY_PORT_DIR}/main.c
${MICROPY_PORT_DIR}/mphalport.c
${MICROPY_DIR}/lib/mp-readline/readline.c
${MICROPY_DIR}/lib/utils/gchelper_generic.c
${MICROPY_DIR}/lib/utils/pyexec.c
${MICROPY_DIR}/lib/utils/stdout_helpers.c
)
target_sources(app PRIVATE
${MICROPY_SOURCE_PY}
${MICROPY_SOURCE_PORT}
)
target_link_libraries(app PRIVATE ${MICROPY_TARGET})
include(${MICROPY_DIR}/py/mkrules.cmake)
I am getting error while running:
CMake error at line 33 :
can't specify sources for target "app" which is not built by this project.
I am taking help from this: https://github.com/micropython/micropython/blob/master/ports/zephyr/CMakeLists.txt , but I think I am missing some steps.

Advice on Makefile and build system structure with a C library

What I want to achieve:
I have a library that has submodules which depend on each other.
I want to have a Makefile for each submodule and then I combine the submodules into one .a file with another Makefile in the root of the repository. The submodules are in their won folders and will compile the .o files into their won obj directories.
What I have now
Makefile that combines the libs:
NAME = libcore.a
HEADERS = arr/inc mem/inc str/inc map/inc
FOLDER = src
MEM = mem
ARR = arr
STR = str
MAP = map
MEM_O = $(wildcard mem/obj/*.o)
ARR_O = $(wildcard arr/obj/*.o)
STR_O = $(wildcard str/obj/*.o)
MAP_O = $(wildcard map/obj/*.o)
OBJ = $(MEM_O) $(ARR_O) $(STR_O) $(MAP_O)
RM = rm -f
all: $(OBJ)
#make -C $(MEM)
#make -C $(ARR)
#make -C $(STR)
#make -C $(MAP)
#ar -rcs $(NAME) $(OBJ)
#echo "\\n\033[32;1mCORE ACTIVATED \033[0m \\n"
clean:
#make clean -C $(MEM)
#make clean -C $(ARR)
#make clean -C $(STR)
#make clean -C $(MAP)
#echo "\\n\033[32;1mCORE DEACTIVATED \033[0m \\n"
fclean: clean
#${RM} ${NAME}
#make fclean -C $(MEM)
#make fclean -C $(ARR)
#make fclean -C $(STR)
#make fclean -C $(MAP)
re: fclean all
.PHONY: all fclean clean re
Makefile for an individual submodule:
NAME = libarr.a
CC = clang
CFLAGS = -O3 -Wall -Wextra -Werror -Wpedantic -Wtype-limits \
-Wunreachable-code -Wpadded -Wshadow -fPIC -Wconversion
SRC_DIR = src/
INC_DIR = inc/
OBJ_DIR = obj/
SRC_BASE = arr_add.c \
arr_add_first.c \
arr_add_last.c \
arr_add_mult.c \
arr_new.c \
arr_put.c \
arr_free.c \
arr_del.c \
arr_del_first.c \
arr_del_last.c \
arr_get.c \
arr_get_first.c \
arr_get_last.c \
arr_iter.c \
arr_iter_range.c \
arr_join.c \
arr_read_file.c \
arr_take.c \
arr_take_first.c \
arr_take_last.c \
arr_search.c \
arr_find.c \
arr_parse.c \
arr_write.c \
arr_null.c \
arr_grow.c \
arr_copy.c \
arr_rotate.c \
SRC = $(addprefix $(SRC_DIR), $(SRC_BASE))
OBJ = $(addprefix $(OBJ_DIR), $(SRC_BASE:.c=.o))
all:
$(MAKE) -j $(NAME)
$(NAME): $(OBJ)
#echo "\\n\033[32;1mARRAY FUNCTIONS COMPILED\033[0m \\n"
$(OBJ_DIR):
#mkdir -p $#
$(OBJ_DIR)%.o: $(SRC_DIR)%.c | $(OBJ_DIR)
#$(CC) $(CFLAGS) -c $< -o $# -I $(INC_DIR)
clean:
#rm -rf $(OBJ_DIR);
fclean: clean
#rm -rf $(NAME);
re: fclean all
.PHONY: all fclean clean re
The problem
Test program compilation:
gcc -fsanitize=undefined -fsanitize=address -fsanitize=leak arr/tests/tests.c libcore.a
There's something wrong with my setup. When I run make for the main Makefile once, the linker won't find the functions in the array library and gives undefined reference. However when I run Make the second time I can then compile my test program correctly. I just can't figure out what I'm doing wrong. My idea is that I create the .o files in the submodule Makefiles and the just basically compile all those .o files with the main Makefile into one .a file.
Thanks in advance for any help on this!
The immediate cause of the error you see is here, in the major makefile:
MEM_O = $(wildcard mem/obj/*.o)
This gives you a list of all object files that exist when the variable MEM_O is expanded, which happens before Make executes any rule. So on the first pass the variable is empty (because there are no object files), the sub-makes build the object files, and the major Make puts nothing into the library (because the variable is empty).
The highest-lever error is that you wrote all of these Makefiles without adequate testing. When you write code, it behooves you to start with something small and simple that works perfectly, then build up. (I really ought to have that hotkeyed by now.)
The mid-level error is that recursive Make is clumsy. It has its uses, but if you handle it carelessly you get errors like this. I suggest a top-level makefile that includes the lower makefiles (by means of the include directive), and lower-level makefiles that can function at either level.

Makefile based on sub-directories

I have a C project program that I want to compile and manage with a makefile:
./include: where headers resides
a.h , b.h , c.h
./obj: where object will be stored
-
./src: where source file resides
main.c , a.c , b.c , c.c
How can I create a makefile to create an executable test , and put object files to obj folder ?
You can use this template I made for simple project. I don't know which compiler you are using but you can configure it with the variables in the first sections as well as other useful configs:
#=============================================================================
# Project related variables
EXENAME = test
FILEIDENTIFIER = .c
COMPFLAGS = -pedantic -Wall
COMPSTANDARD = -std=c11
EXELINKS = -lm
DBARGS = -g
BUILDDIR = build/
BINARY_OUTPUT_DIR = $(BUILDDIR)bin/
OBJDIR = obj/
SOURCEDIRS = src/
INCLUDEDIRS = include/
LIBSDIRS = /usr/lib/
#=============================================================================
# Commands variables
COMPILER = gcc
LINKER = ld -r
DISPLAY = printf
MKDIR = mkdir -p
RMDIR = rmdir
RM = rm -f
#=============================================================================
# Other
VOIDECHO = > /dev/null 2>&1
#=============================================================================
# Semi-automatic variables
EXEFINALOBJ = $(OBJDIR)$(EXENAME).o
EXEFINAL = $(BINARY_OUTPUT_DIR)$(EXENAME)
INCLUDEARGS = $(addprefix -I,$(INCLUDEDIRS))
#=============================================================================
# Automatic variables
SOURCES = $(foreach sourcedir,$(SOURCEDIRS),$(wildcard $(sourcedir)**/*$(FILEIDENTIFIER)) $(wildcard $(sourcedir)*$(FILEIDENTIFIER)))
OBJECTS = $(patsubst %$(FILEIDENTIFIER),%.o,$(foreach sourcedir,$(SOURCEDIRS),$(subst $(sourcedir),$(OBJDIR),$(wildcard $(sourcedir)**/*$( FILEIDENTIFIER)) $(wildcard $(sourcedir)*$(FILEIDENTIFIER)))))
GENERATED_FILES = $(OBJECTS) $(EXEFINALOBJ) $(EXEFINAL)
GENERATED_FOLDERS = $(OBJDIR) $(BINARY_OUTPUT_DIR) $(BUILDDIR)
#=============================================================================
# Special GNU make variables
VPATH = $(SOURCEDIRS)
#=============================================================================
# Rules: Phony Targets
.PHONY: silent
silent:
#make --silent $(EXEFINAL)
.PHONY: all
all: $(EXEFINAL)
.PHONY: debug
debug: COMPFLAGS += $(DBARGS)
debug: all
.PHONY: clean
clean:
#$(DISPLAY) "\n-> Cleaning files...\n"
#$(DISPLAY) " $(foreach file,$(GENERATED_FILES),$(if $(wildcard $(file)),- Removing file $(file)\n,\b))"
#$(RM) $(GENERATED_FILES)
#$(DISPLAY) "\n-> Cleaning folders...\n"
#$(DISPLAY) " $(foreach folder,$(GENERATED_FOLDERS),$(if $(wildcard $(folder)),- Removing folder $(folder)\n,\b))"
#$(RMDIR) $(GENERATED_FOLDERS) $(VOIDECHO) || true
#$(DISPLAY) "\n"
#=============================================================================
# Rules: File Targets
$(EXEFINAL): $(EXEFINALOBJ)
#$(DISPLAY) "\n - Building $# from $^... "
#$(MKDIR) $(BINARY_OUTPUT_DIR)
$(COMPILER) $(EXEFINALOBJ) -o $# $(LIBARGS) $(EXELINKS)
#$(DISPLAY) "Done"
#$(DISPLAY) "\n\n"
$(EXEFINALOBJ): $(OBJECTS)
#$(DISPLAY) "\n - Merging objects files into $#... "
$(LINKER) $(OBJECTS) -o $#
#$(DISPLAY) "Done"
$(OBJDIR)%.o: %$(FILEIDENTIFIER)
#$(DISPLAY) "\n - Building $# from $^... "
#$(MKDIR) $(OBJDIR)
$(COMPILER) $(COMPFLAGS) $(COMPSTANDARD) $(INCLUDEARGS) -c $^ -o $#
#$(DISPLAY) "Done"
The actual configuration is for Linux and uses gcc and ld. It support subfolders for sources and 4 targets are defined:
silent (default): silent build
all: verbose build
debug: debug build
clean: remove files and folders generated by the makefile
If you want to understand exactly how the Makefile work, as MadScientist wrote, look at the GNU make manual at https://www.gnu.org/software/make/manual/html_node/Introduction.html

issues with Makefile in C

#----------------------------------------------------------------------- ------
# Choose a compiler & its options
#--------------------------------------------------------------------------
CC = gcc
OPTS = -W -O3
#--------------------------------------------------------------------------
# Add the debug flag to compile for use by a debugger
#--------------------------------------------------------------------------
#DEBUG=-g
#--------------------------------------------------------------------------
# Add the names of the directories
#--------------------------------------------------------------------------
SRCDIR= src
OBJDIR= obj
INCDIR= include
BINDIR= bin
#--------------------------------------------------------------------
# Add the rest of the source files. Don't forget to add the '\' character
# to continue the line. You don't need it after the last source file
#--------------------------------------------------------------------
SRCS=$(SRCDIR)/Lab12.c \ Function1.c \ Function2.c \ Function3.c \ Function4.c \ Function5.c
#--------------------------------------------------------------------
# You don't need to edit the next few lines. They define other flags
# used in the compilation of the source code
#--------------------------------------------------------------------
INCLUDE = $(addprefix -I,$(INCDIR))
OBJS=${SRCS:$(SRCDIR)/%.c=$(OBJDIR)/%.o}
CFLAGS = $(OPTS) $(INCLUDE) $(DEBUG)
#--------------------------------------------------------------------
# Add the name of the executable after the $(BINDIR)/
#--------------------------------------------------------------------
TARGET = $(BINDIR)/ Lab12
all: $(TARGET)
$(TARGET): $(OBJS)
${CC} ${CFLAGS} -o $# $(OBJS)
$(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
clean:
rm -f $(OBJS)
cleanall:
rm -f $(OBJS)
rm -f Lab12
#--------------------------------------------------------------------
# Add a target named cleanall that will remove the object files as well
# as the executable
#--------------------------------------------------------------------
I have all my "header" files in the include folder. I have all my source code in the src folder (Lab12.c , Function1.c, Function2.c ...). I keep getting this error when i use the make command.
Makefile:45: target Function1.c' doesn't match the target pattern
Makefile:45: target Function2.c' doesn't match the target pattern
Makefile:45: target Function3.c' doesn't match the target pattern
Makefile:45: target Function4.c' doesn't match the target pattern
Makefile:45: target ` Function5.c' doesn't match the target pattern
gcc -W -O3 -Iinclude -c -o Function1.c
gcc: no input files
make: *** [ Function1.c] Error 1
I cant quite figure out why it is behaving this way. All these files are in the src code folder so why isnt the system recognizing them?
SRCS=$(SRCDIR)/Lab12.c \ Function1.c \ Function2.c \ Function3.c \
seems wrong; you should try
SRCS=$(SRCDIR)/Lab12.c Function1.c Function2.c Function3.c
instead
UPDATE
If Function1.c and so on are in ´$(SRCDIR)`, you must prepend the directory to these files, too. (comment from M Oehm)

ld.exe permission denied Makefile gcc

I want to compile and link my Project. I have Problems with linking of the target. It is the first time I`m using a makefile.
I think there may be a Problem with the $OBJ or call of the gcc.
I got the following error message:
C:\Projekte\playground\Modultest>make all
gcc -O0 -g -Wall -fmessage-length=0 -fprofile-arcs -ftest-coverage ./CUnit/headers ./CUnit/sources ./stub ./source ./test --coverage -o CUnit-Target
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find ./CUnit/headers: Permission denied
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find ./CUnit/sources: Permission denied
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find ./stub: Permission denied
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find ./source: Permission denied
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find ./test: Permission denied
collect2.exe: error: ld returned 1 exit status
makefile:54: recipe for target 'CUnit-Target' failed
make: *** [CUnit-Target] Error 1
I have no spaces in the path.
This is my makefile
# makefile to generate UNIT-tests
# define the C compiler to use
CC = gcc
# define any compile-time flags
CFLAGS = -O0 -g -Wall -fmessage-length=0 -fprofile-arcs -ftest-coverage
# define any directories containing header files other than /usr/include
# TODO
HEADERS = ./CUnit/headers \
./CUnit/sources \
./stub \
./source \
./test
SOURCES = ./CUnit/sources \
./stub \
./source \
./test
#TODO Linkerflags
LFLAGS = --coverage -o
# define any libraries to link into executable:
# if I want to link in libraries (libx.so or libx.a) I use the -llibname
# option, something like (this will link in libmylib.so and libm.so:
LIBS =
# TODO define the C source files
TST_SRCS = min.c max.c
SRCS = CUnit.c Automated.c Basic.c Console.c CUCurses.c CUError.c Cunit_intl.c \
MyMem.c TestDB.c TestRun.c Util.c wxWidget.c \
$(TST_SRCS)
# define the C object files
#
# This uses Suffix Replacement within a macro:
# $(name:string1=string2)
# For each word in 'name' replace 'string1' with 'string2'
#OBJ = $(SRCS:%.c=%.o)
#OBJ = $(TST_SRCS:%.c=%.o)
OBJ=$(join($(dir $(SOURCES))), $(notdir $(SRCS:%.c=%.o)))
# define the executable file
TARGET = CUnit-Target
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) $(CFLAGS) $(HEADERS) $(OBJ) $(LFLAGS) $(TARGET)
#echo build finished
#execute tests
#Cunit.exe
# create coverage files
# TODO SRCS max.c min.c ?
# gcov -b -c -f max min
clean:
$(RM) *.o *~ $(MAIN)
# DO NOT DELETE THIS LINE -- make depend needs it

Resources