Makefile target matching - makefile

I'm having troubles with my Makefile :-(
I have a mix of assembly and C sourcecode that I need to link together. I need different build-instructions for those two types. Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
This what I'm trying now:
Get a list of all C files and their resulting output files:
C_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.c")
C_OBJFILES := $(patsub %.c,%.o,$(C_SRCFILES))
Get a list of all asm files and their resulting output files:
A_SRCFILES := $(shell find $(SRCDIRS) -type -f -name "*.asm")
A_OBJFILES := $(patsub %.asm,%.o,$(A_SRCFILES))
When I echo those vars to the screen, they seem to be correct, but how I do define my targets now?
I tried something like this
$(A_OBJFILES): ($A_SRCFILES)
$(AS) $(AFLAGS) -o $# $*
$(C_OBJFILES): ($C_SRCFILES)
$(CC) $(CFLAGS) -c -o $# $*
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $(A_OBJFILES) $(C_OBJFILES) -o $(TARGET_OUTPUT)
but ofcourse, this doesn't work...
Any suggestions?

First problem: a misplaced parenthesis or two.
$(A_OBJFILES): ($A_SRCFILES)
Notice that you have the $ inside the ( in ($A_SRCFILES). Make expands $A, which is nothing, and things go downhill. I think you meant $(A_SRCFILES), and the same thing in the other rule.
Second problem: I don't know the syntax of the assembler, but the syntax of the compiler command is wrong:
$(CC) $(CFLAGS) -c -o $# $*
The variable $* is nothing if we're not in a pattern rule, which we're not (yet). And anyway, if we were in a pattern rule and you were trying to build foo.o, this command would look for the source file foo, and there's no such file. Do it this way:
$(CC) $(CFLAGS) -c -o $# $<
Third problem: each object file depends on all source files (in each rule). Try this instead:
$(A_OBJFILES): %.o : %.asm
...
$(C_OBJFILES): %.o : %.c
...
(Now it's a pattern rule.)
Fourth problem: a lot of redundancy in the last rule. Change it to this:
all: $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $(TARGET_OUTPUT)
or better still:
all: $(TARGET_OUTPUT)
$(TARGET_OUTPUT): $(A_OBJFILES) $(C_OBJFILES)
$(LD) $(LDFLAGS) $^ -o $#

Since both the assembler and C compiler output *.o files, I cannot use the general %.o:%.c construction often found in example Makefiles
Sure you can:
%.o : %.c
# commands to make .o from a corresponding .c
%.o : %.asm
# commands to make .o from a corresponding .asm

Related

Create object files in one folder from different source folders

I am creating a Makefile of a Keil based project. I have a working Makefile now, but I have manually written rules for all the source files, something like this:
out/abc.o: ../../../src/modules/abc.c
ARMCC -o $# $(FLAGS) $^
out/def.o: ../../../src/utilities/def.c
ARMCC -o $# $(FLAGS) $^
out/xyz.o: src/xyz.c
ARMCC -o $# $(FLAGS) $^
which has become kinda long. The object files need to be in one directory(/out), but the source files are in different levels and in various folders like utilities, modules etc. Is there a way to shorten my Makefile so that it scans these different levels of source files and creates the object files?
EDIT:
A follow-up question to the answer. My linker rule is something like this, along with the VPATH addition. I added one directory to VPATH and others are still explicitly compiled.
OBJECT_FILES=out/abc.o out/def.o out/xyz.o
out/binary.axf: $(OBJECT_FILES)
ARMLINK $(MANY_FLAGS) $^ -o $#
VPATH=../a/b/c/module
out/%.o : %.c
$(CC) $(C_FLAGS) $(INCLUDE_PATH) -o $# --depend out/%.d $<
I now get an error that there is no rule for abc.o. abc.c which is present in the directory specified in VPATH under module
*** No rule to make target `out/abc.o', needed by `out/binary.axf'. Stop.
You can use VPATH for this. It can search a list of directories for source files. Assuming you can come up with the list of directories:
VPATH = ../../../src src
CC = ARMCC
out/%.o : %.c
$(CC) -o $# $(CFLAGS) -c $<

GNU make Pattern Rule Fails with 'Main.cpp"

I've got a general-purpose makefile that I've successfully used for small (personal) projects before, as below:
#Makefile to compile a folder's contents into a program.
PROGNAME := MyProgram
LIBRARIES :=
CXX := g++ --std=c++11
INCLUDES := -Isrc -Ihdr
VPATH := src:hdr
CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES))
$(PROGNAME): $(OBJ_FILES)
$(CXX) $(INCLUDES) $(LIBRARIES) $^ -o $# $(ROOTFLAGS)
#Automatically generate dependencies (-MM), change the target to be the
# object file (-MT) and output it to the dependency file (-MF).
%.d: src/%.cpp
$(CXX) $(INCLUDES) -MM -MT '$(patsubst src/%.cpp,obj/%.o,$<)' $< -MF $#
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
.PHONY: clean
clean:
rm obj/*.o $(PROGNAME)
This is designed for the following directory structure:
ParentFolder/
Makefile
hdr/
file1.h
...
src/
file1.cpp
...
obj/
I gave the makefile to a colleague and they found it didn't work - after some investigation, the cause of the problem seems to be that they had a source file called main.cpp in src/, which when running make would give the following error:
make: *** No rule to make target `obj/main.o', needed by `MyProgram'. Stop.
If I rename main.cpp to something else (e.g. test.cpp) then the makefile works as expected.
What is the cause of this behaviour? I've looked through the GNU Make Manual but did not find anything regarding special treatment of files called main.* (in fact, some of the examples use it).
While trying to fix the problem, I found that defining an explicit rule for main.o meant that it would be found - therefore, I presume it's an interaction with the main name and pattern-based rules, but I have not been able to find what that may be.
The trouble is that this rule:
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
requires a corresponding header file. I suspect that there is no hdr/main.h, and Make has no way to build one, so when it is searching for a way to build obj/main.o it considers this rule, rejects it, and finds no other.
I suggest you add another pattern rule (after this one) to handle source files without matching header files:
obj/%.o: src/%.cpp %.d
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
(P.S. Your dependency handling is a little odd and appears to be vestigial -- you generate dependency files and never use them. We can help you with that, once you're building main.o correctly.)

Makefile: source files in a particular directory

What do I need to do if I want to compile several files (e.g. a.f90, b.f90, c.f90) in a given directory (say, MYDIR)?
My Makefile code is something like:
CC=gfortran
CFLAG=-g
HOME=MYDIR
SRC=$(HOME)/(a.f90,b.f90,c.f90)
OBJ=$(SRC:,=.o)
EXE=test.x
%.o: %.f90
$(CC) $(CFLAG) -c -o $# $<
$(EXE): $(OBJ)
$(CC) -o $# $^ $(CFLAG)
clean:
rm -f *.o
I think, the 4-th line is not correct. So what could be the replacement?
Another thought: Can I use a wildcard if I want to compile all .f90 file inside MYDIR?
There are lots of ways to do it. You can do something like:
SRC = $(addprefix $(HOME)/,a.f90 b.f90 c.f90)
Also your assignment of OBJ is wrong; there's no comma needed after the colon.
Yes you can use wildcard if you want.

Passing target name to a dependency in makefile

If I have the following rule in a makefile:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
Every file matching the prefix ./obj/ and sufix .o will have its stem passed to %, so I can provide some dependencies based on its name.
But, suppose I have this kind of rule, which I specify one by one the targets I want:
OBJECTS=abc.o bca.o cba.o
$(OBJECTS): $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
How do I make the % stem actually work for the current target name make is executing? Just using % doesn't work, neither $#.
Note that I'm trying to write the actual target name to its own dependency. For example, when make is executing the rule for abc.o, it would include $(SRC)/abc.c and just it (something like $(patsubst %.o, $(SRC)/%.c, MAGIC_TARGET_NAME_VARIABLE)).
You can just replace this rule:
$(OBJECTS): $(SRC)/%.c
with:
$(OBJECTS) : %.o : $(SRC)/%.c
You will need to add the $(OBJ) to the -o part of the recipe if you still want them built there:
$(OBJECTS) : %.o : $(SRC)/%.c
$(CC) -c -o $(OBJ)/$# $< $(CFLAGS)
I’m not completely clear on what you’re asking, but I think this accomplishes what you’re trying to do:
OBJECTS=abc.o bca.o cba.o
.PHONY: all
all: $(OBJECTS:%=obj/%)
$(OBJ)/%.o: $(SRC)/%.c
echo $(CC) -c -o $# $< $(CFLAGS)
All .o files are built; each .o file is built using only the .c file corresponding to it; and if you want to refer to the list of all object files or source files in the command for compiling a .o file, then you can reference ${OBJECTS} directly.
If this isn’t what you’re trying to do, you’ll be able to get a better answer by listing the input files you have, the output files you want to make, the input dependencies of each output file, and what compilation command you want to execute for each output file.

In gnu make, can the prerequisites in a static pattern rule have different suffixes

Our make file compiles .c source files with a static pattern rule like this:
OBJECTS = foo.o bar.o baz.o
$(OBJECTS): %.o: %.c
$(CC) $< $(C_OPTIONS) -c -o $#
I need to change one of the .c files to an Objective-C .m file. Invoking the compiler is the same for both source types, so I'd like to use the same rule and just tweak it to be more flexible. I'd rather not change the OPTIONS variable because it's also used for the linking step, etc.
Is there a way to make the rule above more flexible to accommodate both .c and .m files?
Thanks
We can add this either-or behavior to the list of things Make should be able to do easily, but isn't. Here's a way to do it, using "eval" to create a seperate rule for each object.
define RULE_template
$(1): $(wildcard $(basename $(1)).[cm])
endef
OBJECTS = foo.o bar.o baz.o
$(foreach obj,$(OBJECTS),$(eval $(call RULE_template,$(obj))))
$(OBJECTS):
$(CC) $&lt $(C_OPTIONS) -c -o $#
Note that this depends on the source files already existing before you run Make (foo.c or foo.m, but not both). If you're generating those sources in the same step, this won't work.
Here's a less clever, more robust method.
CPP_OBJECTS = foo.o bar.o
OBJECTIVE_OBJECTS = baz.o
OBJECTS = $(CPP_OBJECTS) $(OBJECTIVE_OBJECTS)
$(CPP_OBJECTS): %.o: %.c
$(OBJECTIVE_OBJECTS): %.o: %.m
$(OBJECTS):
$(CC) $&lt $(C_OPTIONS) -c -o $#
EDIT: corrected OBJECTS assignment, thanks to Jonathan Leffler.
Not really just copy to
$(OBJECTS): %.o: %.m
$(CC) $< $(C_OPTIONS) -c -o $#
The call to the same compiler is just a happy occasion. Normally you do not compile objective-c code with $(CC). That just feels strange.
But since you go in a harsh way, I won't post do-it-right solution, where you separate objective-C targets from C targets into two different $(OBJECTS)-like variables and make two rules (which you should really do). Too boring. Instead, take a hack!
OBJC_FILES:=$(subst $(wildcard *.m))
real_name = `(test -h $(1) && readlink $(1) ) || echo $(1)`
$(OBJECTS): %.o: %.c
$(GCC) $< $(C_OPTIONS) -c -o $(call real_name,$#)
$(OBJC_FILES): %.c: %.m
ln -s $< $#
And God help those who maintains it!
Btw, this obviously won't work if your m-files are generated.

Resources