compiling *.C and *.S sources from same directory 'make' - makefile

I have been working with a project that only compiles C sources but I've found I need some assembler too, I'm reticent to inline the asm code in a C file as GCC may not interpret it correctly.
My predecesor created the makefile for the project (apologies, it's fairly long):
# Compiler and options
CC := sparc-rtems-gcc
# The application software binary
TARGET := icu_asw
# Source and build directories
SRCDIR := src
BUILDDIR := obj
TARGETDIR := bin
HDSWROOT := ../../hdsw
BSWTOOLS := ../../bsw/sw/tools
SRCEXT := c
DEPEXT := d
OBJEXT := o
MRAMEXT := img.elf
# Flags, libraries and includes
CFLAGS := -std=gnu99 -Wall -Wextra -g
LIBDRV := $(HDSWROOT)/lib/libdrv.a
INCFLAGS := -I$(HDSWROOT)/include -I$(HDSWROOT)/osal/rtems
# Debug flags
DEBUGFLAGS = -DLOGERROR=1 -DLOGWARN=1 -DLOGDEBUG=1 -DLOGINFO=1 -DMAKECHECKS=1
NODEBUGFLAGS = -DLOGERROR=1 -DLOGWARN=0 -DLOGDEBUG=0 -DLOGINFO=0 -DMAKECHECKS=1
#-----------------------------------------------------------------------
# Build instructions
#-----------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
# Default make
all: $(TARGET)
# Remake
remake: cleaner all
# Clean only objects
clean:
#$(RM) -rf $(BUILDDIR)
# Full clean (objects and binaries)
cleaner: clean
#$(RM) -rf $(TARGETDIR)
# Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
# Link (uses an order-only prerequisite for the directories so that they
# don't affect the use of the $^)
$(TARGET): $(OBJECTS) | directories
$(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIBDRV)
# Make the build and target directories
directories:
#mkdir -p $(TARGETDIR)
#mkdir -p $(BUILDDIR)
# Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $(INCFLAGS) $(NODEBUGFLAGS) -c -o $# $<
#$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
#cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
#sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
#sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
#rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
# Non-File Targets
.PHONY: all remake clean cleaner
I want to also bring in and compile two .S files, so, I edited the following line
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT) -or -name *.$(ASMEXT))
To bring in the .S files, then I edited the OBJECTS to also include the ASM sources ("*.S")
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)),$(SOURCES:.$(ASMEXT)=.$(OBJEXT)))
But when recompiling with 'make all' I'm getting:
$ make all
make: *** No rule to make target `obj/asi_access.S', needed by `icu_asw'. Stop.
I don't suppose someone could spot where I am going wrong? I think I have not correctly added to the OBJECTS line!
Thanks

The expression $(var:.ext1=.ext2) does not filter by .ext1, i.e.
$(SOURCES:.$(SRCEXT)=.$(OBJEXT)) $(SOURCES:.$(ASMEXT)=.$(OBJEXT))
gives for a test source list the following result
a.o b.o c.S a.c b.c c.o
I.e. you duplicated your files and you have source files in the OBJECTS definition.
The following would be a correct approach:
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%, \
$(patsubst %.$(SRCEXT),%.$(OBJEXT), \
$(patsubst %.$(ASMEXT),%.$(OBJEXT),$(SOURCES)) \
) \
)
UPDATE: you should consider to use 2 separate object lists, so that you can apply different rules for them, e.g.
SOURCES_C := $(filter %.$(SRCEXT),$(SOURCES))
OBJECTS_C := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES_C:%.$(SRCEXT)=%.$(OBJEXT)))
SOURCES_ASM := $(filter %.$(ASMEXT),$(SOURCES))
OBJECTS_ASM := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES_ASM:%.$(ASMEXT)=%.$(OBJEXT)))
$(OBJECTS_C): $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
.... C compiler recipe ....
$(OBJECTS_ASM): $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(ASMEXT)
.... assembler recipe ....
$(TARGET): $(OBJECTS_C) $(OBJECTS_ASM) | directories

Related

Why does my makefile never stop building?

I am trying to create a makefile to control the build process. I use eclipse and I have a lot of projects some of which are shared libraries. So if I build a project that is using a library, then I would like the library to be built if it is out of date. The seems pretty standard. I just cannot make it work.
I am making the linking dependent on the libraries, and I (try to) provide a rule for building the libraries. But when I do it this way, it seems to be building the library over and over again - and it never finishes. What am I missing?
CPPUTEST_HOME = ...
PROJECTROOT := ...
SDKTARGETSYSROOT := /opt/fsl-imx-fb/4.14-sumo/sysroots/cortexa9hf-neon-poky-linux-gnueabi
COMPONENT_NAME := Jehova
USER_LIB :=
INCLUDE_DIRS := $(PROJECTROOT)/Log/source \
$(PROJECTROOT)/Config/source \
LIBS := $(PROJECTROOT)/Log/bin/libLog.so \
$(PROJECTROOT)/Config/bin/libConfig.so \
# Links to the commands to be used
REMOVE := rm -rf
COMPILER := arm-poky-linux-gnueabi-g++
# All of the sources participating in the build are defined here
SOURCEDIR = source
OBJECTDIR = objects
TEST_DIR = utest
PATH_TO_MAIN = source/main.cpp
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)
OBJECTS = $(patsubst $(SOURCEDIR)/%.cpp, $(OBJECTDIR)/%.o, $(SOURCES))
DEPENDENCIES = $(patsubst $(SOURCEDIR)/%.cpp, $(OBJECTDIR)/%.d, $(SOURCES))
# Paths to the headerfiles
get_dirs_from_dirspec = $(wildcard $1)
INCLUDE_DIRS += $(USER_LIB) \
$(SDKTARGETSYSROOT)/usr/include/ \
$(SDKTARGETSYSROOT)/usr/include/c++/7.3.0/ \
$(SDKTARGETSYSROOT)/usr/include/c++/7.3.0/arm-poky-linux-gnueabi/
INCLUDE_DIR_EXPANDED = $(call get_dirs_from_dirspec, $(INCLUDE_DIRS))
COMPILE_INCLUDE = $(foreach dir, $(INCLUDE_DIR_EXPANDED), -I$(dir))
LINK_INCLUDE = $(foreach dir, $(INCLUDE_DIR_EXPANDED), -L$(dir))
# Compiler and linkerflags
COMPILER_FLAGS := -Wall -c -fmessage-length=0 -march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a9 -Wno-unknown-pragmas --sysroot=$(SDKTARGETSYSROOT)
LINKER_FLAGS := -mfloat-abi=hard -lpthread
# If main.cpp does not exist the project is assumed to be a shared library
ifeq ("$(wildcard $(PATH_TO_MAIN))","")
COMPILER_FLAGS += -fPIC
LINKER_FLAGS += -shared -o
BIN := ./bin/lib$(COMPONENT_NAME).so
else
LINKER_FLAGS += -o
BIN := ./bin/$(COMPONENT_NAME)
endif
# Optimization and debug levels
ifeq ($(MAKECMDGOALS),release)
COMPILER_FLAGS += -O3
else
COMPILER_FLAGS += -O0 -g3
endif
# Include dependencies
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPENDENCIES)),)
-include $(DEPENDENCIES)
endif
endif
# All Target
all: $(BIN) test
-$(REMOVE) makeenv
# Compile source to create object files
./objects/%.o: ./source/%.cpp
#echo 'Building file: $<'
#echo 'Invoking: Cross G++ Compiler'
-$(COMPILER) $(COMPILE_INCLUDE) $(COMPILER_FLAGS) -MMD -MP -MF"$(#:%.o=%.d)" -MT"$(#)" -o "$#" "$<"
#echo 'Finished building: $<'
#echo ' '
# Link objects to build target
$(BIN): $(OBJECTS) $(LIBS)
#echo 'Building target: $#'
#echo 'Invoking: Cross G++ Linker'
-$(COMPILER) $(LINK_INCLUDE) --sysroot=$(SDKTARGETSYSROOT) $(LINKER_FLAGS) $(BIN) $(OBJECTS) $(LIBS)
#echo 'Finished building target: $#'
#echo ' '
# All Target release build
release: clean $(BIN)
-$(REMOVE) makeenv
# Run the test
test: $(BIN)
make -C $(TEST_DIR)
# Other Targets
clean:
-$(REMOVE) $(OBJECTS)$(DEPENDENCIES) $(BIN)
make -C $(TEST_DIR) clean
-$(REMOVE) makeenv
-#echo ' '
$(LIBS):
-cd $(PROJECTROOT)/Config && $(MAKE) clean all release
-cd $(PROJECTROOT)/Log && $(MAKE) clean all release

GNU Make correct behaviour when including other makefiles

I have the following makefile in the root of the project:
Makefile
# Board version
# Available: 3
PI ?= 3
# Kernel binaries
ifeq ($(PI), 3)
KERNEL_IMG := kernel8.img
else ifeq ($(PI), 2)
KERNEL_IMG := kernel7.img
else ifeq ($(PI), 1)
KERNEL_IMG := kernel.img
else
$(error Unsupported Raspberry Pi version)
endif
KERNEL_ELF := $(patsubst %.img,%.elf,$(KERNEL_IMG))
# Directories/paths
BUILD_DIR := build
# Toolchain
TOOLCHAIN ?= aarch64-elf
OBJCOPY := $(TOOLCHAIN)-objcopy
LD := $(TOOLCHAIN)-ld
CC := $(TOOLCHAIN)-gcc
# Misc
LINKER_SCRIPT := linker.ld
# Flags
LDFLAGS := -T $(LINKER_SCRIPT)
ASFLAGS :=
CFLAGS :=
# Source files
C_SRC := $(wildcard *.c)
ASM_SRC := $(wildcard *.S)
# Include
include pi/$(PI)/mod.mk
# Object files
OBJECTS := $(patsubst %,$(BUILD_DIR)/%.o,$(C_SRC))
OBJECTS += $(patsubst %,$(BUILD_DIR)/%.o,$(ASM_SRC))
# Targets
.PHONY: all builddirs clean
all: $(BUILD_DIR)/$(KERNEL_IMG)
$(BUILD_DIR)/$(KERNEL_IMG): $(BUILD_DIR)/$(KERNEL_ELF)
$(OBJCOPY) $< -O binary $#
$(BUILD_DIR)/$(KERNEL_ELF): $(LINKER_SCRIPT) $(OBJECTS)
$(LD) $(OBJECTS) $(LDFLAGS) -o $#
$(OBJECTS): | builddirs
builddirs: $(BUILD_DIR)/pi/$(PI)
$(BUILD_DIR)/pi/$(PI):
mkdir -p $#
$(BUILD_DIR)/%.S.o: %.S
$(CC) -c $< $(ASFLAGS) -o $#
$(BUILD_DIR)/%.c.o: %.c
$(CC) -c $< $(CFLAGS) -o $#
clean:
$(RM) -r $(BUILD_DIR)
It includes pi/3/mod.mk
C_SRC +=
ASM_SRC += pi/3/start.S
$(BUILD_DIR)/pi/3/start.S.o: pi/3/start.S pi/3/include/cpu/sysregs.h
$(CC) -c $< $(ASFLAGS) -o $#
Now here's the problem: whenever I run 'make' in the root of a project, '$(BUILD_DIR)/pi/3/start.S.o' rule invokes, instead of 'all'. If I move 'include pi/$(PI)/mod.mk' to the very bottom of the root makefile, and replace 'C_SRC' and 'ASM_SRC' variables in 'pi/3/mod.mk' with 'OBJECTS += $(BUILD_DIR)/pi/3/start.S.o' and invoke 'make', this rule isn't even invoked, so I get an error that make doesn't know how to build start.S.o.
What am I doing wrong and what is the best way to handle this?
Make's default goal is the first target in your Makefile. In your case the first target is the one defined in the included Makefile: $(BUILD_DIR)/pi/3/start.S.o. Either invoke make all or move the all rule in your Makefile such that it becomes the first one, or tell make that the default goal is all:
.DEFAULT_GOAL := all
(see GNU make manual).

What does this make rule do?

I am writing makefile by example of another and have stumbled upon this target rule:
ifeq ($(MAKECMDGOALS),build_executable)
$(firstword $(dependency_files)): $(application_path)/config/gcc/app.mk
#rm -rf $(object_output_path)
-include $(dependency_files)
endif
This is placed between other rules. This makefile runs recursively reinvoking itself with different goals.
All variables pretty much explains themself. Prerequisite app.mk contains just configuration by some variables set which are used in this make file. Dependency files variable constructed like this:
dependency_files := $(object_files:%.o=%.d)
My question is what "common practice" this rule corresponds to, what does it do and why it is like that. If my understanding is correct (please correct me if I am wrong), I do understand that first of all it includes all dependency files if they exist. Then this rule may be ran by "makeflow". What I do not understand is the intention of doing this. Also, what is the trigger of running this rule on that one (basically the random one) dependency file since .d files are generated with GCC -MMD -MP options.
Thanks in advance.
EDIT:
###############################################################################
#
# #brief This file is part of the TouchGFX 4.8.0 evaluation distribution.
#
# #author Draupner Graphics A/S <http://www.touchgfx.com>
#
###############################################################################
#
# #section Copyright
#
# This file is free software and is provided for example purposes. You may
# use, copy, and modify within the terms and conditions of the license
# agreement.
#
# This is licensed software for evaluation use, any use must strictly comply
# with the evaluation license agreement provided with delivery of the
# TouchGFX software.
#
# The evaluation license agreement can be seen on www.touchgfx.com
#
# #section Disclaimer
#
# DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Draupner Graphics A/S has
# no obligation to support this software. Draupner Graphics A/S is providing
# the software "AS IS", with no express or implied warranties of any kind,
# including, but not limited to, any implied warranties of merchantability
# or fitness for any particular purpose or warranties against infringement
# of any proprietary rights of a third party.
#
# Draupner Graphics A/S can not be held liable for any consequential,
# incidental, or special damages, or any other relief, or for any claim by
# any third party, arising from your use of this software.
#
###############################################################################
# Get name of this Makefile
makefile_name := $(lastword $(MAKEFILE_LIST))
# Get path of this Makefile
makefile_path := $(dir $(abspath $(makefile_name)))
# Get path where the Application is
application_path := $(abspath $(makefile_path)/../..)
# Change makefile_name to a relative path
makefile_name := $(patsubst $(application_path)/%,%,$(abspath $(makefile_name)))
# Get relative path to makefile
makefile_path_relative = $(patsubst $(application_path)/%,%,$(makefile_path))
# Get path to bsp
bsp_path := $(patsubst $(application_path)/%,%,$(abspath $(makefile_path_relative)../bsp))
# Get OS path
os_path := $(patsubst $(application_path)/%,%, $(abspath $(makefile_path_relative)../CMSIS-RTOS2))
# Get target path
cmsis_core_path := $(patsubst $(application_path)/%,%, $(abspath $(makefile_path_relative)../CMSIS-COREM))
# Get identification of this system
ifeq ($(OS),Windows_NT)
UNAME := MINGW32_NT-6.2
else
UNAME := $(shell uname -s)
endif
board_name := NONE
platform := cortex_m4f
.PHONY: all clean assets flash intflash
ifneq ($(words $(makefile_path))$(words $(MAKEFILE_LIST)),11)
all: $(filter clean,$(MAKECMDGOALS))
all clean assets flash intflash:
$(error Spaces not allowed in path)
else
all: $(filter clean,$(MAKECMDGOALS))
all clean assets:
#cd $(application_path) && $(MAKE) -r -f $(makefile_name) -s $(MFLAGS) _$#_
flash intflash: all
#cd $(application_path) && $(MAKE) -r -f $(makefile_name) -s $(MFLAGS) _$#_
# Directories containing application-specific source and header files.
# Additional components can be added to this list. make will look for
# source files recursively in comp_name/src and setup an include directive
# for comp_name/include.
components := gui target generated/gui_generated
# Location of folder containing bmp/png files.
asset_images_input := assets/images
# Location of folder to search for ttf font files
asset_fonts_input := assets/fonts
# Location of folder where the texts.xlsx is placed
asset_texts_input := assets/texts
build_root_path := build
object_output_path := $(build_root_path)/$(board_name)
binary_output_path := $(build_root_path)/bin
# Location of output folders where autogenerated code from assets is placed
asset_root_path := generated
asset_images_output := $(asset_root_path)/images
asset_fonts_output := $(asset_root_path)/fonts
asset_texts_output := $(asset_root_path)/texts
#include application specific configuration
include $(application_path)/config/gcc/app.mk
os_source_files := $(os_path)/RTX/Config/RTX_Config.c \
$(os_path)/RTX/Source/rtx_lib.c
os_include_paths := $(os_path)/Include \
$(os_path)/RTX/Config \
$(os_path)/RTX/Include
#$(os_path)/RTX/Source \
os_wrapper := $(os_path)/OSWrappers_cmsis.cpp
### END OF USER SECTION. THE FOLLOWING SHOULD NOT BE MODIFIED ###
ifeq ($(UNAME), Linux)
imageconvert_executable := $(touchgfx_path)/framework/tools/imageconvert/build/linux/imageconvert.out
fontconvert_executable := $(touchgfx_path)/framework/tools/fontconvert/build/linux/fontconvert.out
else
imageconvert_executable := $(touchgfx_path)/framework/tools/imageconvert/build/win/imageconvert.out
fontconvert_executable := $(touchgfx_path)/framework/tools/fontconvert/build/win/fontconvert.out
st_link_executable := "$(PROGRAMFILES)\\STMicroelectronics\\STM32 ST-LINK Utility\\ST-LINK Utility\\ST-LINK_CLI.exe"
st_link_external_loader := "$(PROGRAMFILES)\\STMicroelectronics\\STM32 ST-LINK Utility\\ST-LINK Utility\\ExternalLoader\\N25Q128A_STM32469I-DISCO.stldr"
endif
target_executable := target.elf
target_hex := target.hex
########### include $(touchgfx_path)/config/toolchain-arm-none-eabi-gcc.mk #################
# Defines the assembler binary and options. These are optional and only
# of relevance if the component includes source files with an
# extension of .asm.
# Consider adding -Wall to c_compiler_options and cpp_compiler_options
#no_libs := -nostdlib -nodefaultlibs For now, include everything.
assembler := arm-none-eabi-gcc
assembler_options += -g \
-nostartfiles -fno-exceptions\
$(no_libs) -mthumb -mno-thumb-interwork \
-Wall
assembler_options += $(float_options)
c_compiler := arm-none-eabi-gcc
c_compiler_options += -g \
-nostartfiles -mthumb -fno-exceptions \
-mno-thumb-interwork -std=c99 \
$(no_libs) \
-Os -fno-strict-aliasing -fdata-sections -ffunction-sections
c_compiler_options += $(float_options)
cpp_compiler := arm-none-eabi-g++
cpp_compiler_options += -g -mthumb \
-nostartfiles $(no_libs) \
-mno-thumb-interwork -fno-rtti -fno-exceptions \
-Os -fno-strict-aliasing -fdata-sections -ffunction-sections
cpp_compiler_options += $(float_options)
linker := arm-none-eabi-g++
linker_options += -g -Wl,-static -nostartfiles -mthumb $(no_libs) -mno-thumb-interwork \
-fno-exceptions -fno-rtti \
-Os -fno-strict-aliasing -Wl,--gc-sections
objcopy := arm-none-eabi-objcopy
archiver := arm-none-eabi-ar
strip := arm-none-eabi-strip
####################### Additional toolchain configuration for Cortex-M4f targets.##########################
float_abi := hard
float_options := -mfpu=fpv4-sp-d16
ifneq ("$(float_abi)","hard")
float_options += -mfloat-abi=softfp
else
float_options += -mfloat-abi=hard
endif
assembler_options += -mcpu=cortex-m4 -march=armv7e-m -Wno-psabi $(float_options) -DCORE_M4 -D__irq=""
c_compiler_options += -mcpu=cortex-m4 -march=armv7e-m -Wno-psabi $(float_options) -DCORE_M4 -D__irq=""
cpp_compiler_options += -mcpu=cortex-m4 -march=armv7e-m -Wno-psabi $(float_options) -DCORE_M4 -D__irq=""
linker_options += -mcpu=cortex-m4 -march=armv7e-m -Wno-psabi $(float_options)
############################################################################################################
#include everything + specific vendor folders
framework_includes := $(touchgfx_path)/framework/include
#this needs to change when assset include folder changes.
all_components := $(components) \
$(asset_fonts_output) \
$(asset_images_output) \
$(asset_texts_output)
#keep framework include and source out of this mess! :)
include_paths := $(library_includes) $(foreach comp, $(all_components), $(comp)/include) $(framework_includes) $(source_bsp_paths)
source_paths = $(foreach comp, $(all_components), $(comp)/src)
# Finds files that matches the specified pattern. The directory list
# is searched recursively. It is safe to invoke this function with an
# empty list of directories.
#
# Param $(1): List of directories to search
# Param $(2): The file pattern to search for
define find
$(foreach dir,$(1),$(foreach d,$(wildcard $(dir)/*),\
$(call find,$(d),$(2))) $(wildcard $(dir)/$(strip $(2))))
endef
unexport find
fontconvert_ttf_lower_files := $(call find, $(asset_fonts_input), *.ttf)
fontconvert_ttf_upper_files := $(call find, $(asset_fonts_input), *.TTF)
fontconvert_otf_lower_files := $(call find, $(asset_fonts_input), *.otf)
fontconvert_otf_upper_files := $(call find, $(asset_fonts_input), *.OTF)
fontconvert_bdf_lower_files := $(call find, $(asset_fonts_input), *.bdf)
fontconvert_bdf_upper_files := $(call find, $(asset_fonts_input), *.BDF)
fontconvert_font_files := $(fontconvert_ttf_lower_files) \
$(fontconvert_ttf_upper_files) \
$(fontconvert_otf_lower_files) \
$(fontconvert_otf_upper_files) \
$(fontconvert_bdf_lower_files) \
$(fontconvert_bdf_upper_files)
source_files := $(call find, $(source_paths),*.cpp)
gcc_source_files := $(touchgfx_path)/framework/config/gcc/stdio.c \
$(touchgfx_path)/framework/config/gcc/stdlib.c \
$(touchgfx_path)/framework/config/gcc/string.c
# bsp files
board_c_files := \
$(bsp_path)/src/main.c \
$(bsp_path)/src/debug.c
board_cpp_files := \
$(bsp_path)/src/leds.cpp \
$(bsp_path)/src/KeySampler.cpp \
$(bsp_path)/src/app_gpio.cpp
# bsp include
board_include_paths := \
$(bsp_path)/inc \
gui/include \
generated/gui_generated/include
# Compiler options
c_compiler_options += -DST -DSTM32F469xx -DUSE_OS_SYSTICK -DUSE_FLOATING_POINT -g -gdwarf-2
cpp_compiler_options += -DST -DSTM32F469xx -DUSE_OS_SYSTICK -DUSE_FLOATING_POINT -g -gdwarf-2
include_paths += $(application_path)/platform/os $(board_include_paths) $(os_include_paths)
c_source_files := $(call find, $(source_paths),*.c) $(os_source_files) $(makefile_path_relative)/isr.c $(board_c_files)
source_files += $(os_wrapper) target/gcc/gccstubs.cpp target/main.cpp \
$(board_cpp_files) \
$(bsp_path)/src/BoardConfiguration.cpp \
$(bsp_path)/src/GPIO.cpp
object_files := $(source_files:$(touchgfx_path)/%.cpp=$(object_output_path)/touchgfx/%.o) $(c_source_files:$(touchgfx_path)/%.c=$(object_output_path)/touchgfx/%.o)
object_files := $(object_files:%.cpp=$(object_output_path)/%.o)
object_files := $(object_files:%.c=$(object_output_path)/%.o)
dependency_files := $(object_files:%.o=%.d)
textconvert_script_path := $(touchgfx_path)/framework/tools/textconvert
textconvert_executable := $(call find, $(textconvert_script_path), *.rb)
text_database := $(asset_texts_input)/texts.xlsx
libraries := touchgfx-float-abi-hard RTX_CM4F
library_include_paths := $(touchgfx_path)/lib/core/$(platform)/gcc
library_include_paths += $(os_path)/RTX/Library/GCC
.PHONY: _all_ _clean_ _assets_ _flash_ _intflash_ generate_assets build_executable
# Force linking each time
.PHONY: $(binary_output_path)/$(target_executable)
_all_: generate_assets
ifeq ($(shell find $(application_path) -wholename "$(application_path)/$(binary_output_path)/extflash.bin" -size +0c | wc -l | xargs echo),1)
_flash_: _extflash_
else
_flash_: _intflash_
endif
_extflash_:
#$(st_link_executable) -c -P $(binary_output_path)/target.hex 0x90000000 -Rst -EL $(st_link_external_loader)
_intflash_:
#$(st_link_executable) -c -P $(binary_output_path)/intflash.hex 0x08000000 -Rst
generate_assets: _assets_
#$(MAKE) -f $(makefile_name) -r -s $(MFLAGS) build_executable
build_executable: $(binary_output_path)/$(target_executable)
$(binary_output_path)/$(target_executable): $(object_files)
#echo Linking $(#)
#mkdir -p $(#D)
#mkdir -p $(object_output_path)
#$(file >$(build_root_path)/objects.tmp) $(foreach F,$(object_files),$(file >>$(build_root_path)/objects.tmp,$F))
#$(linker) \
$(linker_options) -T $(makefile_path_relative)/application.ld -Wl,-Map=$(#D)/application.map $(linker_options_local) \
$(patsubst %,-L%,$(library_include_paths)) \
#$(build_root_path)/objects.tmp -o $# \
-Wl,--start-group $(patsubst %,-l%,$(libraries)) -Wl,--end-group
#rm -f $(build_root_path)/objects.tmp
#echo "Producing additional output formats..."
#echo " target.hex - Combined internal+external hex"
#$(objcopy) -O ihex $# $(#D)/target.hex
#echo " intflash.elf - Internal flash, elf debug"
#$(objcopy) --remove-section=ExtFlashSection $# $(#D)/intflash.elf 2>/dev/null
#echo " intflash.hex - Internal flash, hex"
#$(objcopy) -O ihex --remove-section=ExtFlashSection $# $(#D)/intflash.hex
#echo " extflash.bin - External flash, binary"
#$(objcopy) -O binary --only-section=ExtFlashSection $# $(#D)/extflash.bin
$(object_output_path)/touchgfx/%.o: $(touchgfx_path)/%.cpp $(application_path)/config/gcc/app.mk
#echo Compiling $<
#mkdir -p $(#D)
#$(cpp_compiler) \
-MMD -MP $(cpp_compiler_options) $(cpp_compiler_options_local) $(user_cflags) \
$(patsubst %,-I%,$(include_paths)) \
-c $< -o $#
$(object_output_path)/%.o: %.cpp $(application_path)/config/gcc/app.mk
#echo Compiling $<
#mkdir -p $(#D)
#$(cpp_compiler) \
-MMD -MP $(cpp_compiler_options) $(cpp_compiler_options_local) $(user_cflags) \
$(patsubst %,-I%,$(include_paths)) \
-c $< -o $#
$(object_output_path)/%.o: %.c $(application_path)/config/gcc/app.mk
#echo Compiling $<
#mkdir -p $(#D)
#$(c_compiler) \
-MMD -MP $(c_compiler_options) $(c_compiler_options_local) $(user_cflags) \
$(patsubst %,-I%,$(include_paths)) \
-c $< -o $#
ifeq ($(MAKECMDGOALS),build_executable)
$(firstword $(dependency_files)): $(application_path)/config/gcc/app.mk
#rm -rf $(object_output_path)
-include $(dependency_files)
endif
_assets_: BitmapDatabase $(asset_texts_output)/include/texts/TextKeysAndLanguages.hpp
alpha_dither ?= no
dither_algorith ?= 2
remap_identical_texts ?= yes
.PHONY: BitmapDatabase
BitmapDatabase:
#echo Converting images
#$(imageconvert_executable) -dither $(dither_algorithm) -alpha_dither $(alpha_dither) -opaque_image_format $(opaque_image_format) -non_opaque_image_format $(non_opaque_image_format) $(screen_orientation) -r $(asset_images_input) -w $(asset_images_output)
$(asset_texts_output)/include/texts/TextKeysAndLanguages.hpp: $(text_database) $(application_path)/config/gcc/app.mk $(textconvert_executable) $(fontconvert_executable) $(fontconvert_font_files)
#rm -f $(asset_fonts_output)/src/*
#rm -f $(asset_fonts_output)/include/fonts/*
#rm -f $(asset_fonts_output)/UnicodeList*.txt
#rm -f $(asset_fonts_output)/CharSizes*.csv
#mkdir -p $(asset_texts_output)/include/texts
#ruby $(textconvert_script_path)/main.rb $(text_database) $(fontconvert_executable) $(asset_fonts_output) $(asset_texts_output) $(asset_fonts_input) . $(remap_identical_texts) $(text_data_format)
_clean_:
#echo Cleaning
#rm -rf $(build_root_path)
# Do not remove gui_generated
#rm -rf $(asset_images_output)
#rm -rf $(asset_fonts_output)
#rm -rf $(asset_texts_output)
# Create directory to avoid error if it does not exist
#mkdir -p $(asset_root_path)
# Remove assets folder if it is empty (i.e. no gui_generated folder)
#rmdir --ignore-fail-on-non-empty $(asset_root_path)
endif
Changing the app.mk file might make the dependency files obsolete. What this rule does is forcing the re-building of the dependency files by deleting their directory.
For instance the dependencies may change because preprocessor symboles where added or modified. Let's assume that in the provided example the c_compiler_options has been modified to add the -DUSE_FLOATING_POINT option:
c_compiler_options += -DST -DSTM32F469xx -DUSE_OS_SYSTICK -DUSE_FLOATING_POINT -g -gdwarf-2
In a source file this may add or remove include file directives:
#ifdef USE_FLOATING_POINT
#include <some_file.h>
#else
#incude <anotherfile.h>
#endif
Hence the need for running the dependendy evaluation again.

Compile two targets with one Makefile

---Full Makefile at the bottom ---
I'm currently finishing a project, so I'm coming to the packaging/compiling part.
I'm working with Make, and the specificity of my project is that it contains two projects with a main() in each of them.
I want a binary of the first project (named 'shell') and a binary of the second one (named 'ls'). I've edited the Makefile to separate targets, sources files, etc. Here are the important lines:
-- Projects --
TARGET_SHELL = shell
TARGET_LS = ls
-- Directories --
SOURCE = ./src
BIN = ./bin
DIRLIST = ${SOURCE} ${BIN}
-- Targets --
BINSHELL = ${TARGET_SHELL:%=${BIN}/%}
BINLS = ${TARGET_LS:%=${BIN}/%}
-- Files --
SRC_SHELL = ${wildcard ${SOURCE}/execution.c ${SOURCE}/shell.c}
SRC_LS = ${wildcard ${SOURCE}/commande_ls.c}
INT_SHELL = ${wildcard ${SOURCE}/execution.h}
INT_LS = ${wildcard ${SOURCE}/commande_ls.h}
OBJ_SHELL = ${SRC_SHELL:%.c=%.o}
OBJ_LS = ${SRC_LS:%.c=%.o}
-- Rules --
all : ${BINSHELL} ${BINLS}
-- Binaries --
${BIN}/${TARGET_SHELL} : ${${TARGET_SHELL}:%=${SOURCE}/%}
${BIN}/${TARGET_LS} : ${${TARGET_LS}:%=${SOURCE}/%}
${BIN}/% : $(OBJ_SHELL)
#echo
#echo Linking bytecode : $#
#echo ----------------
#echo
${CC} -o $# $^ ${LDFLAGS}
#echo
#echo Done
#echo
The 'make' command works perfectly. At the end, I have two binaries, one named 'shell' and the other one named 'ls'. Nice!
But in fact, the two binaries are exactly the same, they both execute the 'shell' project. I wanted the binary 'shell' to execute the 'shell' project, and the binary named 'ls' to execute the 'ls' project...
I know that I have to edit the end of the Makefile, but I don't know what :(
Thanks
#/// #file
#/// #brief Generic Makefile for the System 2 project.
#
#/// #detail If you just add some library files used by the project.c program, you have nothing to change to compile them if sources are in the ./src directory. To add a new binary, just add the name of the main file in the TARGETS variable.
#Nom du project
TARGET_SHELL = shell
TARGET_LS = ls
##############
# Constantes #
##############
# Repertoires
SOURCE = ./src
BIN = ./bin
DOCPATH = ${SOURCE}/dox
DOCTARGET = ./doc
DIRLIST = ${SOURCE} ${BIN}
#DEP = ${SOURCE}/depend
#DIRLIST = ${SOURCE} ${BIN} ${OPT} ${DEP}
# Cibles
BINSHELL = ${TARGET_SHELL:%=${BIN}/%}
BINLS = ${TARGET_LS:%=${BIN}/%}
# Commandes
CC = gcc
# Options
CFLAGS = -O0 -g -W -Wall -Wextra -Wconversion -Werror -mtune=native -march=native -std=c99 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
LDFLAGS = -lm -W -Wall -pedantic -L. -lm
# Fichiers
DOX = ${wildcard ${DOCPATH}/*.dox} # Sources
SRC_SHELL = ${wildcard ${SOURCE}/divers.c ${SOURCE}/commandes_externes.c ${SOURCE}/commandes_internes.c ${SOURCE}/entities.c ${SOURCE}/execution.c ${SOURCE}/parse.c ${SOURCE}/shell.c} # Sources
SRC_LS = ${wildcard ${SOURCE}/commande_ls.c}
INT_SHELL = ${wildcard ${SOURCE}/divers.h ${SOURCE}/commandes_externes.h ${SOURCE}/commandes_internes.h ${SOURCE}/execution.h ${SOURCE}/parse.h} # Interfaces
INT_LS = ${wildcard ${SOURCE}/commande_ls.h}
OBJ_SHELL = ${SRC_SHELL:%.c=%.o} # Objets
OBJ_LS = ${SRC_LS:%.c=%.o}
##########
# Regles #
##########
# ALL
all : ${BINSHELL} ${BINLS}
# CLEAN
clean :
#echo
#echo Cleaning : object files
#echo --------
#echo
rm -f ${OBJ_SHELL}
rm -f ${OBJ_LS}
clean-doc :
#echo
#echo Cleaning : object files
#echo --------
#echo
rm -fr ${DOCTARGET}
clean-emacs :
#echo
#echo Cleaning : emacs back-ups
#echo --------
#echo
rm -f ${SOURCE}/*~
rm -f ${SOURCE}/\#*\#
rm -f *~
rm -f \#*\#
clean-bin :
#echo
#echo Cleaning : binaries
#echo --------
#echo
rm -f ${BINSHELL}
rm -f ${BINLS}
distclean : clean clean-emacs clean-bin
dirs :
#for dir in ${DIRLIST} ;\
do \
echo Creating directory : $${dir} ;\
echo ------------------ ;\
if test -d $${dir} ;\
then \
echo Directory already exists ;\
else mkdir -p $${dir} ;\
fi ;\
echo Done ;\
echo ;\
done
# Binaires
${BIN}/${TARGET_SHELL} : ${${TARGET_SHELL}:%=${SOURCE}/%}
${BIN}/${TARGET_LS} : ${${TARGET_LS}:%=${SOURCE}/%}
${BIN}/% : $(OBJ_SHELL)
#echo
#echo Linking bytecode : $#
#echo ----------------
#echo
${CC} -o $# $^ ${LDFLAGS}
#echo
#echo Done
#echo
# Regles generiques
%.o : %.c %.h
#echo
#echo Compiling $#
#echo --------
#echo
$(CC) $(CFLAGS) -c $< -o $#
# Documentation
doc : ${SRC} ${INT} ${DOX}
doxygen; doxygen
#############################
# Inclusion et spécificités #
#############################
.PHONY : all clean clean-doc clean-emacs clean-bin distclean doc
Some fun with very dynamic makefile:
#
# Boilerplate.
#
define add_target
$(info add_target($1))
$(eval $(eval_args))
$(eval $(call eval_args,$1,\
OBJDIR := $(firstword $($1.OBJDIR) ./objs/$1),\
))
$(eval $(call eval_args,$1,\
objs := $(obj_from_source),
))
$(eval $1 := $($1.TARGET))
TARGETS += $($1)
PHONY_TARGETS += $1
CLEAN_TARGETS += clean_$1
.PHONY: clean_$1
clean_$1:; rm -rf $($1.OBJDIR) $($1)
.PHONY: $1
$1: $($1)
$($1): target:=$1
$($1): $($1.objs); $$(if $$(wildcard $$(#D)),,mkdir -p $$(#D) && )$$(add_target.link)
$($1.objs):; $$(if $$(wildcard $$(#D)),,mkdir -p $$(#D) && )$$(add_target.compile)
$(foreach $1.SOURCES,$($1.SOURCES),$(eval $(obj_from_source): $($1.SOURCES)))
$(info end)
endef
void :=
space := $(void) $(void)
obj_from_source = $(addprefix $($1.OBJDIR)/,$(addsuffix .o,$(basename $(notdir $($1.SOURCES)))))
eval_args = $(foreach i,2 3 4 5 6 7 8 9,$(call eval_arg,$1,$(strip $($i))))
eval_arg = $(if $2,$(info $(space)$(space)$1.$2)$(eval $1.$2))
# Link command line
add_target.link = $(CC) $($(target).LDLAGS) -o $# $^
# Compile command line
add_target.compile = $(CC) -c -o $# $($(target).CFLAGS) $<
# -- Directories --
SOURCE := ./src
BIN := ./bin
# Add 'shell' target to the project
$(eval $(call add_target,shell,\
TARGET := $(BIN)/shell,\
SOURCES += ${SOURCE}/execution.c,\
SOURCES += ${SOURCE}/shell.c,\
CFLAGS := -Wall -I./include,\
))
# Add 'ls' target to the project
$(eval $(call add_target,ls,\
TARGET := $(BIN)/ls,\
SOURCES := $(addprefix ${SOURCE}/,execution.c commande_ls.c),\
CFLAGS := -I./include,\
))
all: ${PHONY_TARGETS}
.PHONY: all
clean: | $(CLEAN_TARGETS)
.PHONY: clean
Environment:
$ find
.
./include
./include/execution.h
./src
./src/commande_ls.c
./src/execution.c
./src/shell.c
Source files:
$ for f in `find -type f`; do echo $f; cat $f; echo; done
./include/execution.h
void workload();
./src/commande_ls.c
#include <stdio.h>
#include "execution.h"
int main() {
printf("Welcome to ls\n");
workload();
}
./src/execution.c
#include <stdio.h>
#include "execution.h"
void workload() {
printf("Hello from %s\n", __FILE__);
}
./src/shell.c
#include <stdio.h>
#include "execution.h"
int main() {
printf("Welcome to shell\n");
workload();
}
Build all targets:
$ make -f ../Makefile.sample
add_target(shell)
shell.TARGET := ./bin/shell
shell.SOURCES += ./src/execution.c
shell.SOURCES += ./src/shell.c
shell.CFLAGS := -Wall -I./include
shell.OBJDIR := ./objs/shell
shell.objs := $(obj_from_source)
end
add_target(ls)
ls.TARGET := ./bin/ls
ls.SOURCES := ./src/execution.c ./src/commande_ls.c
ls.CFLAGS := -I./include
ls.OBJDIR := ./objs/ls
ls.objs := $(obj_from_source)
end
mkdir -p objs/shell && cc -c -o objs/shell/execution.o -Wall -I./include src/execution.c
cc -c -o objs/shell/shell.o -Wall -I./include src/shell.c
mkdir -p bin && cc -o bin/shell objs/shell/execution.o objs/shell/shell.o
mkdir -p objs/ls && cc -c -o objs/ls/execution.o -I./include src/execution.c
cc -c -o objs/ls/commande_ls.o -I./include src/commande_ls.c
cc -o bin/ls objs/ls/execution.o objs/ls/commande_ls.o
Run targets:
$ ./bin/ls.exe; ./bin/shell.exe
Welcome to ls
Hello from src/execution.c
Welcome to shell
Hello from src/execution.c
Clean ls and build all targets again (just for fun):
$ make -f ../Makefile.sample clean_ls
add_target(shell)
shell.TARGET := ./bin/shell
shell.SOURCES += ./src/execution.c
shell.SOURCES += ./src/shell.c
shell.CFLAGS := -Wall -I./include
shell.OBJDIR := ./objs/shell
shell.objs := $(obj_from_source)
end
add_target(ls)
ls.TARGET := ./bin/ls
ls.SOURCES := ./src/execution.c ./src/commande_ls.c
ls.CFLAGS := -I./include
ls.OBJDIR := ./objs/ls
ls.objs := $(obj_from_source)
end
rm -rf ./objs/ls ./bin/ls
$ make -f ../Makefile.sample
add_target(shell)
shell.TARGET := ./bin/shell
shell.SOURCES += ./src/execution.c
shell.SOURCES += ./src/shell.c
shell.CFLAGS := -Wall -I./include
shell.OBJDIR := ./objs/shell
shell.objs := $(obj_from_source)
end
add_target(ls)
ls.TARGET := ./bin/ls
ls.SOURCES := ./src/execution.c ./src/commande_ls.c
ls.CFLAGS := -I./include
ls.OBJDIR := ./objs/ls
ls.objs := $(obj_from_source)
end
mkdir -p objs/ls && cc -c -o objs/ls/execution.o -I./include src/execution.c
cc -c -o objs/ls/commande_ls.o -I./include src/commande_ls.c
cc -o bin/ls objs/ls/execution.o objs/ls/commande_ls.o
Note how handy $(add_target) function is. It provides way add as many targets to your project as you need without stupid code duplication. Still configuring of target build options is extremely flexible.
Should work with GNU Make 3.81 and up. Enjoy!
Did you try something like this:
SUBDIRS := common programs
all: subdir
ifdef SUBDIRS
.PHONY: subdir $(SUBDIRS)
subdir: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -s -C $# <-- ${BIN...
endif
SUBDIRS --> TARGET...

Outputting obj files to obj directory in Makefile

Hi I wrote this Makefile by modifying this example: https://sites.google.com/site/michaelsafyan/software-engineering/how-to-write-a-makefile
program_NAME := bin/myprogram
SRC_DIR := src
#
#srces
#
program_C_SRCS := $(wildcard $(SRC_DIR)/*.c)
program_CXX_SRCS := $(wildcard $(SRC_DIR)/*.cpp)
#
#obj files
#
program_C_OBJS := ${program_C_SRCS:.c=.o}
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_C_OBJS) $(program_CXX_OBJS)
#
# include and library dirs; also libraries
#
program_INCLUDE_DIRS := inc
program_LIBRARY_DIRS :=
program_LIBRARIES :=
# flags
CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))
#
# targets
#
.PHONY: all clean distclean
all: $(program_NAME)
$(program_NAME): $(program_OBJS)
$(LINK.cc) $(program_OBJS) -o $(program_NAME)
clean:
#- $(RM) $(program_NAME)
#- $(RM) $(program_OBJS)
distclean: clean
It works in the following way. The classes below are compiled into an executable "myprogram" which is output in the bin directory. The only issue is the object files are created inside the src folder, instead of the obj folder. How can I modify this makefile such that obj files are created in the obj folder? Thank you.
/project
Makefile
/src
Class1.cpp
Class2.cpp
main.cpp
/obj
/bin
myProgram
/inc
Class1.h
Class2.h
To start with, you could use e.g. the subst function to replace the source-file directory with the object-file directory:
program_OBJS = $(subst $(SRC_DIR),$(OBJ_DIR),$(program_C_OBJS))
program_OBJS += $(subst $(SRC_DIR),$(OBJ_DIR),$(program_CXX_OBJS))
Of course you now need to add a target for object-file creation, as these will not be put in the correct place otherwise:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c -o $# $<
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $<
Try with something like:
OUT_DIR=obj
program_bare_OBJS := $(program_C_OBJS) $(program_CXX_OBJS)
program_OBJS=$(addprefix $(OUT_DIR)/,$(program_bare_OBJS))

Resources