substituting folder path in $(SOURCES) of a makefile - makefile

I am looking for a way to substitute the folder on a list of source files variable within makefile.
Is there something that works here?
I start off by finding my source files
program_C_SRCS := $(wildcard $(SRCDIR)/*.c)
program_CXX_SRCS := $(wildcard $(SRCDIR)/*.cpp)
the results (if I understand GNU makefiles correctly) look typically like
src/main.cpp
src/sensor.cpp
then I build by object files
program_C_OBJS := ${program_C_SRCS:.c=.o}
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.opp}
this replaces the extensions of my source files as per expected.
Finally, I want to replace "src/" with "obj/"
program_C_OBJPATH := ${subst $(SRCDIR) , $(OBJDIR) , $(program_C_OBJS)}
program_CXX_OBJPATH := ${subst $(SRCDIR) , $(OBJDIR) , $(program_CXX_OBJS)}
However, this does not work.
I have gone through the GNU makefile website to no avail. This solution Makefile to put object files from source files different directories into a single, separate directory? comes close but the objects directory must be explicitly included everywhere and the sources directory does not include source path information.
In my makefile the list of source files include the path and I would prefer that the list of object files include the corresponding object directory, too.
The rest of the makefile tries also to use variables
linking stage
$(program_NAME): $(program_OBJS)
$(CXX) $(CFLAGS) $(CXXFLAGS) $(LDFLAGS) $(program_OBJS) -o "$(program_NAME)"
compile stage
%.opp : %.cpp | mkdirobjdir
$(CXX) $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c -o "$#" "$<"
and finally the rules
main_enose.opp : main_enose.cpp core_enose.cpp core_enose.h
$(OBJDIR)/core_enose.opp : core_enose.cpp core_enose.h
$(OBJDIR)/core_enose.h :

Your problem here is the spaces around the commas in the $(subst) calls. make isn't ignoring them the way you expect it might. It is seeing them as literal values in the string to find, the string to replace and the to do the replacement in.
Remove them.
program_C_OBJPATH := ${subst $(SRCDIR),$(OBJDIR),$(program_C_OBJS)}
program_CXX_OBJPATH := ${subst $(SRCDIR),$(OBJDIR),$(program_CXX_OBJS)}
That said you probably either want to use $(patsubst) to limit where the replacement happens:
program_C_OBJPATH := $(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(program_C_OBJS))
program_CXX_OBJPATH := $(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(program_CXX_OBJS))
or you want to use $(notdir) and $(addprefix) to handle stripping all the directory information and adding it back:
program_C_OBJPATH := $(addprefix $(OBJDIR)/,$(notdir $(program_C_OBJS)))
program_CXX_OBJPATH := $(addprefix $(OBJDIR)/,$(notdir $(program_CXX_OBJS)))

Related

Makefile do not regenerate main target after delete it

I learning to write makefile. I meet a problem today. My makefile makes the main target successfully. Then I delete the main target and run the "make" command again. But the makefile did not make the main target, just show "make: `main.o' is up to date". I don't know why. Here is my makefile and folder structure:
CXX := g++
FLAGS := -std=c++11
INCLUDE_DIR := $(shell find . -type d)
SOURCE_DIR := $(INCLUDE_DIR)
SOURCE_FILE := $(foreach dir, $(SOURCE_DIR), $(wildcard $(dir)/*.cpp))
OBJECT_FILE := $(SOURCE_FILE:%.cpp=%.o)
-include $(OBJECT_FILE:%.o=%.d)
TARGET := app
all: $(TARGET)
$(TARGET): $(OBJECT_FILE)
$(CXX) $(FLAGS) -o $# $(OBJECT_FILE)
$(OBJECT_FILE): %.o: %.cpp | $(SOURCE_DIR)
$(CXX) $(FLAGS) -c $< -o $# -MD -MF $(#:.o=.d)
./-----main.cpp
|---test
|---func.h
|---func.cpp
Unless you choose a specific target to be built on the command line (via make <target>), make will always choose the first target it sees in the makefile as the default target to be built
Consider these lines in your makefile:
-include $(OBJECT_FILE:%.o=%.d)
TARGET := app
all: $(TARGET)
When nothing is built, there are no .d files so the -include doesn't include anything. Then make finds the target all and uses that as the default.
The second time through the makefile, there are .d files so the -include command includes them. Those files define some targets, the first of which is main.o, and so now that is the first target and built by default.
You should move your -include down to the end of the makefile and ensure that the all target is always the first one built.
Just as an aside, I don't know if it's an artifact of your cut and paste into SO, but many of your lines have extra whitespace at the end. You should be aware that extra whitespace at the end of lines IS SIGNIFICANT in makefiles, in many places. I highly recommend using an editor that will allow you to visualize whitespace and/or automatically strip extra whitespace at the end of lines.

Makefile wildcard and variable expansion

I have this Makefile (abbreviated):
COMPILE = armcc
LINK = armlink
SRCDIR := ./src1 \
./src2
INCLUDES := -I ./inc
CSRC := $(wildcard $(SRCDIR)/*.c)
# CSRC := ./src1/*.c ./src2/*.c
OBJS := $(CSRC:.c=.o)
.PHONY: clean
clean:
#echo "Clean Finished"
%.o: %.c
#echo Compiling $<
#$(COMPILE) $(INCLUDES) $< -o $#
mktest: $(OBJS) Makefile
#echo $(CSRC)
#echo $(OBJS)
#echo building mktest
#$(LINK) -o mktest.axf
When I run it the wildcard only expanded for the last entry in the SRCDIR variable, which is ./src2. The output shown below.
c:> make mktest
./src1 ./src2/file2.c
./src1 ./src2/file2.o
building mktest
If I replace the line where CSRC defined, with the line below it. It works fine, and the output shown below.
c:> make mktest
./src1/*.c ./src2/*.c
./src1/*.o ./src2/*.o
building mktest
This is OK if I only have a few sub-directories I want to include. But if I want to include more, the Makefile will become ugly. Am I not using the wildcard function properly here?
What you would need your CSRC definition to be is:
CSRC:= $(foreach dir,$(SRCDIR),$(wildcard $(dir)/*))
If you look at the documentation:
$(wildcard pattern…)
This string, used anywhere in a makefile, is replaced by a space-separated list of names of existing files that match one of the given file name patterns…
This means your original line actually reads as:
CSRC := $(wildcard src1/ src2/*.c)
That is files whose names are matching against src1/ or src2/*.c.

Fortran Makefile Error and Questions

I'm trying to make my own Makefile for a Fortran code. It looks very alike to another Makefile, which can perfectly work. But unfortunately I can't find out what's wrong by myself. The configuration is described below:
I have a main folder containing sub-folders name src, lib, results, mod, obj. Makefile itself is also in the main folder. I have several fortran sources files in the src folder, say main.f90, subroutine_1.f90, subroutine_2.f90, module_1.f90 and module_2.f90. Subroutine_1 and subroutine_2 are included in module_1, module_2 in also used in module_1. In this case I only need main.f90 and module_*.f90 to be included in my Makefile(if that's not wrong). I also have a static library to be used.
# For WINDOWS
RM := del
PS := $(strip \)
#--------------------- DICTIONARY ---------------------
BUILD_DIR := .
SRC_DIR := $(BUILD_DIR)$(PS)src
LIB_DIR := -L$(BUILD_DIR)$(PS)lib
TAR_DIR := $(BUILD_DIR)$(PS)results
MOD_DIR := $(BUILD_DIR)$(PS)mod
OBJ_DIR := $(BUILD_DIR)$(PS)obj
#------------------ COMPILER AND FLAG ------------------
FC := gfortran
FCFLAGS := -g -c -fbacktrace -fno-align-commons -fbounds-check\
-J"$(MOD_DIR)"
FLFLAGS :=
#------------------- TARGET & SOURCE--------------------
TARGET := $(TAR_DIR)$(PS)main.exe
SRC := $(notdir $(wildcard $(SRC_DIR)$(PS)module_*.f90))\
main.f90
LIB := -lfftw3-3.lib
LDFLAGS := $(LIB_DIR)
OBJ := $(patsubst %.f90, $(OBJ_DIR)$(PS)%.o, $(notdir $(SRC)))
all: $(TARGET)
# Final linking
$(TARGET): $(OBJ)
$(FC) $(FLFLAGS) -o $# $(OBJ) $(LDFLAGS) $(LIB) #line a
$(OBJ_DIR)$(PS)%.o: $(SRC_DIR)$(PS)%.f90
$(FC) $(FCFLAGS) -o $# $< #line b
clean:
-$(RM) -f $(OBJ_DIR)$(PS)*.o
-$(RM) -f $(MOD_DIR)$(PS)*.mod
I got many errors from the make process but I guess they all come from the same place.
$ make
Makefile:line a: warning: overriding recipe for target '.'
Makefile:line b: warning: ignoring old recipe for target '.'
make: Circular . <- . dependency dropped.
make: *** No rule to make target 'src\%.f90', needed by '.'. Stop.
Except from the error, I also have several questions:
How to choose appropriate flags for compiling?
Since module_2 is used in module_1, do I need to compile them in order? In reality I have many modules so I don't think I'm able to specify that one by one...
When do I need to create a dependency .d file? I don't quite know how it works.
Do I need to compile .mod out of .o? For example add a line
%.mod: %.o
Thanks a lot.

.cpp to .o files in Makefile

How can I generate .o file corresponding to all the .cpp files in a directory using Makefile?
I have a directory that contains .cpp files. Now, I want to compile them in .o files. The name of the .o files should be same as corresponding .cpp files. What should I do?
Actually, I already had an implementation but I am not sure how it work
SRCS := $(wildcard $(SRCDIR)/*.cpp)
OBJS := $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
$(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
// Recipe //
Try this
SRCS=$(wildcard *.cpp)
OBJS=$(SRCS:.cpp=.o )
%.o: %.cpp
$(CC) -c $< -o $#
Let me add some more explaination to it.
SRCS := $(wildcard $(SRCDIR)/*.cpp) - It will list all the .cpp files under SRCDIR directory and will assign to SRCS
OBJS := $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o) - It will replace all the files with .cpp listed from the above statement to .o ex: main.cpp would be changed to main.o and assigned to OBJS
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp - Object files depends on respective .cpp files and in the rule you can write rule to create object files
The % character can be used for wildcard pattern-matching, to provide generic targets. For example:
%.o: %.c
[TAB] actions
When % appears in the dependency list, it is replaced with the same string that was used to perform substitution in the target.
If the above explanation is not clear just go through the Makefile Basics once and try writing without using special variables and then go to the complex rules.

Generic target/rule to build all source files from a list, outputting objects to one directory

I am trying to make one generic target in my makefile that will builds sources from mixed directories and output the object files to on single directory.
We have a source structure that is mixed in various directories (like said above, below is just an example)
SRCS = ../a/b/source1.c \
b/source2.c \
../c/source3.c
But I would like all of the object files to output to the directory ./objs (same directory level as 'b')
To do this I was trying the following
OBJS = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))
$(OBJS): %.o : $(filter %/$(basename $(notdir %)).c, $(SRCS))
echo "dependencies: $^" # shows up empty
$(CC) $(filter %/$(basename $(notdir $#)).c, $(SRCS)) -o $# # This works and finds the proper source file
$(CC) $^, $(SRCS)) -o $# # I would like to use this, but as I said the dependencies show up blank
There is a weird problem with this however, and I don't understand where the problem is.
In the dependency it doesn't match anything, but in the recipe it does match properly.
Now the weird part (for me atleast). If I try and test out by hard coding one of the paths then it match for ALL files in that path
$(OBJS): %.o : $(filter ../a/b/$(basename $(notdir %)).c, $(SRCS)) # matches for all files in "../a/b" directory
But using SECONDEXPANSION and hardcoding the directory it works
.SECONDEXPANSION:
$(OBJS): %.o : $$(filter ../a/b/$$(basename $$(notdir %)).c, $(SRCS))
And also not using SECONDEXPANSION and hardcoding the source file name works
$(OBJS): %.o : $(filter %source1.c, $(SRCS)) # Hardcoding source1.c works for source1.c
But it seems like I can't combine to two do what I want for some reason. I have tried secondexpansion stuff (thoguht I'm not really sure why I would need it in this case) and could never get anything working that way either.
I am trying to avoid manually declaring targets for each file individually i.e.
objs/source1.o : ../a/b/source1.c
Because our real world example has tons of files and it would be nice to have less to maintain. I feel like I am very close to getting it.
I am using Cygwin with GNU Make 4.0.
After googling a few more times I finally came across the fix here:
http://lists.gnu.org/archive/html/help-make/2010-09/msg00062.html
I still don't know exactly why I needed to use the SECONDEXPANSION ($$-ness) at all but in practice it doesn't work without it. But basically I needed to create a variable for the '%' sign. Doing the following works for me.
SRCS = ../a/b/source1.c \
b/source2.c \
../c/source3.c
OBJS = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))
.SECONDEXPANSION:
PERCENT = %
$(OBJS): %.o : $$(filter $$(PERCENT)/$$(notdir %).c, $(SRCS))
$(CC) $< -o $#
This now builds source1.c, source2.c, and source3.c and outputs the object files into the objs/ directory.
What I didn't mention in my question but I knew all along was that this will only work if you have unique file names for all source files. But we are okay with that limitation (obviously).

Resources