Basically, I have a file 'blah.txt'. That files gets parsed by a 'compiler' and from it will generate N output .c files. I want a makefile that will from that .txt file generate the c files then compile all of them and archive them in a libmystuff.a
I tought of something like this :
all: dogen libmystuff.a
dogen: source.txt
mycompiler $^
libmystuff.a: $(addsuffix .o, $(shell ls *.c))
$(AR) rcs $# $^
.PHONY: dogen
But obviously that doesn't work because the dependencies are evaluated at the start and at that point the *.c just doesn't yield anything yet since they don't exist.
Does anyone see how to accomplish that (without listing all the generated *.c explicitely) ?
Use sentry "makefile" to force make to re-read makefile and substitute correct list at *.c:
include sources-sentry
sources-sentry: source.txt
mycompiler $^
touch $#
libmystuff.a: $(addsuffix .o, $(shell ls *.c))
$(AR) rcs $# $^
include directive is used to include other makefiles (just like C's #include). It has a nice pecularity that if makefile it includes is a target itself, make program first considers it as a target and tries to update. If it is not up-to-date, make invokes the commands needed to update it and then re-reads makefile, substituting all the variables again.
Thus, if source.txt changed since the last time you processed it (the time being recorded as timestamp of sources-sentry file), the sources will be updated and make will be re-invoked, the *.c being substituted to the updates set of c-files.
Pavel Shved is right(*), you must rerun Make. Here is a trick I'm rather proud of. It will handle dependencies on objects that may not yet exist, and won't run unnecessarily.
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
all: libmystuff.a
ifeq ($(MAKELEVEL),0)
libmystuff.a: source.txt
mycompiler $^
#$(MAKE) -s $#
else
libmystuff.a: $(OBJECTS)
$(AR) rcs $# $^
endif
(*) My old nemesis, we meet again.
EDIT:
If some other make calls this make... I hadn't thought of that. But I think this will solve it:
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:.c=.o)
all: libmystuff.a
libmystuff.a: source.txt
mycompiler $^
#$(MAKE) -s phonyLib
.PHONY: phonyLib
phonyLib: $(OBJECTS)
$(AR) rcs libmystuff.a $^
(Yes, I know, if you feel an urge to build a file called "phonyLib" you won't be able to do it with this makefile, but let's not be perverse.)
If your .c files are only produced by the .txt, then you can let the libmystuff.a depend on the txt, and evaluate the $(shell ls *.c) in the rule body instead.
Related
I am kinda rookie in makefile field but trying to write makefile that would go in two modes: normal mode make outputing executable file called say bingo depending on some files and a mode make debug outputing executable file called bingo.debug that shall be compiled with debug option. I'm trying to use target variable with the following result:
PROGRAM = bingo
SUFIX = .debug
CC = gcc
CFLAGS = -Wall -O2
DEBUG = -g -D DEBUG
all: $(PROGRAM)
debug: CFLAGS += $(DEBUG)
debug: PROGRAM += $(SUFIX)
debug: all
file1.o: file1.c file1.h
$(CC) -c $(CFLAGS) -o $# $<
file2.o: file2.c file2.h
$(CC) -c $(CFLAGS) -o $# $<
$(PROGRAM).o: $(PROGRAM).c
$(CC) -c $(CFLAGS) -o $# $<
$(PROGRAM): file1.o file2.o ($PROGRAM).o
$(CC) -o $# $^
.PHONY: all clean
clean:
rm -rf $(PROGRAM) *.o
It looks like make debug correctly compiles the file with debug flags but it does not change the file name (i.e. both modes outputs the same bingo file). Any help much appriciated!
You cannot use target-specific variables in targets. The documentation is very clear that they are available only in recipes.
In general it's problematic to do things this way, because make has no idea which objects were built with debug and which weren't. If you forget to do a complete clean and/or run make the wrong way then you'll get a mix of different object files: some compiled with debug and some not.
Instead, you should put your debug object files in a different directory from your non-debug object files so you don't have to worry about that.
I have a makefile of this kind:
program: \
a/a.o \
b/b.o
$(CXX) $(CXXFLAGS) -o program \
a/a.o \
b/b.o
a.o: \
a/a.cpp \
a/a.h
$(CXX) $(CXXFLAGS) -c a/a.cpp
b.o: \
b/b.cpp \
b/b.h
$(CXX) $(CXXFLAGS) -c b/b.cpp
So in the directory of the makefile I have two subdirectories a and b
that contain respectively a.h, a.cpp and b.h, b.cpp.
The problem is that if I modify a .cpp file, issuing a make rebuilds the target program
but if I modify an .h file make do not rebuilds anything but says
make: `program' is up to date.
I can't understand why, because the .h files are in the prerequisites line
along with the .cpp files.
Interestingly, if I issue a make on an object file target like
$ make a.o
instead, the modifications to a/a.h
are detected and the target a/a.o is rebuild.
Where is the problem?
The subdirectories that you added to the question later are causing the problem indeed. The target program depends on a/a.o and b/b.o, but there are no explicit rules to make those to .o files -- only the targets a.o and b.o are present but those are not in the subdirectories.
Therefore, make will look for implicit rules to build a/a.o and b/b.o. That rule does exist, you will see it being found when you run make -d. That implicit rule depends on a/file_a.cpp only, not on a/file_a.h. Therefore, changing a/file_a.cpp will make a/a.o out of date according to that implicit rule, whereas a/file_a.h will not.
For your reference, the make User's Manual has a section Catalogue of Implicit Rules. That also explains that you can use the argument --no-builtin-rules to avoid that implicit behavior. If you use that, you will see that make can not find any rules to make a/a.o and b/b.o.
Finally, running make a.o will run the recipe for the target a.o as defined in your makefile. That target does have a/a.h as its prerequisite so any change to that file will result in a recompile. But essentially, that has nothing to do with the target program, which has different prerequisites.
I have written a (GNU make) Makefile designed to perform automatic dependency tracking in header includes. Everything works great except that upon typing make a second time, the entire code base rebuilds. Only typing make the third time and successive times gives the message that nothing is to be done.
SRCDIR := src
INCDIR := inc
ifeq ($(DEBUG),1)
OBJDIR := debug_obj
BINDIR := debug_bin
else
OBJDIR := obj
BINDIR := bin
endif
BINS := prog1 prog2 prog3 prog4
SRCS := $(wildcard $(SRCDIR)/*.cpp)
OBJS := $(patsubst $(SRCDIR)/%,$(OBJDIR)/%,$(SRCS:.cpp=.o))
DEPS := $(OBJS:.o=.d)
CC := g++
COMMON_FLAGS := -Wall -Wextra -Werror -std=c++11 -pedantic
ifeq ($(DEBUG),1)
CXX_FLAGS := $(COMMON_FLAGS) -Og -g
else
CXX_FLAGS := $(COMMON_FLAGS) -O3 -D NDEBUG
endif
all: $(addprefix $(BINDIR)/,$(BINS)) | $(BINDIR)
$(OBJDIR) $(BINDIR):
# mkdir -p $#;
$(BINDIR)/%: $(OBJDIR)/%.o | $(BINDIR)
$(CC) $(CPP_FLAGS) $< -o $#;
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $(OBJDIR)
$(CC) $(CPP_FLAGS) -MMD -MP -c $< -o $#;
-include $(DEPS)
.PHONY: all clean
clean:
- rm -f $(OBJS);
- rm -f $(DEPS);
- rm -f $(addprefix $(BINDIR)/,$(BINS));
- rmdir $(OBJDIR) $(BINDIR) 2> /dev/null || true
Clearly some dependency had changed, so I tried running make -n -d | grep 'newer' following the first invocation of make, which shows this:
Prerequisite obj/prog1.o' is newer than targetbin/prog1'.
Prerequisite obj/prog2.o' is newer than targetbin/prog2'.
Prerequisite obj/prog3.o' is newer than targetbin/prog3'.
Prerequisite obj/prog4.o' is newer than targetbin/prog4'.
And ls -la obj/*
Showed the existence of the dependency (*.d) files but not the object (*.o) files. I assume that this is related to how g++ -MMD -MP works, but despite the apparent absence of object files, binaries are present after the first make.
The answer to this question suggests that both are generated at the same time, and man g++ does not dispute this as far as I can tell.
I've read a couple other questions and answers related to automatic dependency tracking, but I don't see this issue arising. Why is this happening? Can you suggest a fix?
Update
A more careful look at the first invocation of make shows this unexpected (to me) line at the end:
rm obj/prog1.o obj/prog2.o obj/prog3.o obj/prog4.o
That answers one question but raises another.
Update
I also found this in the debugging output.
Considering target file `prog1'.
File `prog1' does not exist.
make: *** No rule to make target `prog1'. Stop.
No implicit rule found for `prog1'.
Finished prerequisites of target file `prog1'.
Must remake target `prog1'.
For which I note that prog1 is missing the bin/ prefix. Nothing explains why the first run removes the object files, but the second run leaves them, however. That seems to be at the heart of the issue.
make was treating the object files as intermediates and deleting them accordingly. Adding:
.SECONDARY: $(OBJS)
solved the problem. I do not know why it was doing this the first invocation but not the second invocation. Comments are welcome.
The reason that the .o files are not present is that they're considered intermediate files so make deletes them. However, that shouldn't cause any problems in your build, because as long as make can envision the intermediate file it will realize it doesn't need to be rebuilt if its prerequisites are older than its parents (in this case, as long as prog1 is newer than prog1.cpp for example).
I was not able to reproduce your experience with the second build rebuilding everything. More details will be needed. The output you showed is not interesting because that's just saying that make does NOT need to rebuild the .o file (it's newer than the prerequisite). You need to find the lines in the output that explain why make does need to rebuild the .o file. If you provide that info we may be able to help.
Just a couple of comments on your makefile: first, I don't think it's a good idea to force the mkdir rule to always succeed. If the mkdir fails you WANT your build to fail. Probably you did this so it would not be a problem if the directory already exists, but that's not needed because the mkdir -p invocation will never fail just because the directory exists (but it will fail if the directory can't be created for other reasons such as permissions). Also you can combine those into a single rule with multiple targets:
$(BINDIR) $(OBJDIR):
#mkdir -p $#
Next, you don't need the semicolons in your command lines and in fact, adding them will cause your builds to be slightly slower.
Finally, a small nit, but the correct order of options in the compile line is -c -o $# $<; the source file is not (this is a common misconception) an argument to the -c option. The -c option, like -E, -s, etc. tells the compiler what output to create; in the case of -c it means compile into an object file. Those options do not take arguments. The filename is a separate argument.
is there a way to set a output-directory for making kernel-modules inside my makefile?
I want to keep my source-direcory clean from the build-files.
KBUILD_OUTPUT and O= did not work for me and were failing to find the kernel headers when building externally.
My solution is to symlink the source files into the bin directory, and dynamically generate a new MakeFile in the bin directory. This allows all build files to be cleaned up easily since the dynamic Makefile can always just be recreated.
INCLUDE=include
SOURCE=src
TARGET=mymodule
OUTPUT=bin
EXPORT=package
SOURCES=$(wildcard $(SOURCE)/*.c)
# Depends on bin/include bin/*.c and bin/Makefile
all: $(OUTPUT)/$(INCLUDE) $(subst $(SOURCE),$(OUTPUT),$(SOURCES)) $(OUTPUT)/Makefile
make -C /lib/modules/$(shell uname -r)/build M=$(PWD)/$(OUTPUT) modules
# Create a symlink from src to bin
$(OUTPUT)/%: $(SOURCE)/%
ln -s ../$< $#
# Generate a Makefile with the needed obj-m and mymodule-objs set
$(OUTPUT)/Makefile:
echo "obj-m += $(TARGET).o\n$(TARGET)-objs := $(subst $(TARGET).o,, $(subst .c,.o,$(subst $(SOURCE)/,,$(SOURCES))))" > $#
clean:
rm -rf $(OUTPUT)
mkdir $(OUTPUT)
If you are building inside the kernel tree you can use the O variable:
make O=/path/to/mydir
If you are compiling outside the kernel tree (module, or any other kind of program) you need to change your Makefile to output in a different directory. Here a little example of a Makefile rule which output in the MY_DIR directory:
$(MY_DIR)/test: test.c
gcc -o $# $<
and then write:
$ make MY_DIR=/path/to/build/directory
The same here, but I used a workaround that worked for me:
Create a sub-directory with/for every arch name (e.g. "debug_64").
Under "debug_64": create symbolic link of all .c and .h files. Keeping the same structure.
Copy the makefile to "debug_64" and set the right flags for 64 Debug build, e.g.
ccflags-y := -DCRONO_DEBUG_ENABLED
ccflags-y += -I$(src)/../../../lib/include
KBUILD_AFLAGS += -march=x86_64
Remember to set the relative directories paths to one level down, e.g. ../inc will be ../../inc.
Repeat the same for every arch/profile.
Now we have one source code, different folders, and different make files.
By the way, creating profiles inside make files for kernel module build is not an easy job, so, I preferred to create a copy of makefile for every arch.
I am asked to write a Makefile which needs to selects between two compilers, and each of these compilers should support 3 build versions (debug, release, test).
There are a lot of variables that change based on input (compiler, compiler options, output directory, include directories etc). My first option was to go through target-specific variables and configure variables according to target. Do you think this is good idea?
I am not extremely familiar with those kind of variables. It seems to me that if I do something like this:
release: variable1=value1 #release is target
release: variable2=value2
release:
# some compilation rule
Only the variable1 will be configured. Am I right about this?
Update
Thank you for your reply. I am trying to deal with compiler selection issue through additional variable which would be configured according to target. But, here is the problem. I have the following lines:
release: CFLAGS = -DCORE_SW_VERSION='"$(CORE_SW_VERSION)"' -Wall
release: CFLAGS += -fgnu89-inline -mno-volatile-cache $(INCLUDE)
release: TARGET=release
After this lines, I do some ifeq sequence in which I decide which compiler to use (according to TARGET variable value).
And CFLAGS is configured properly, but the TARGET variable is empty. This leads me to conclusion that you can configure only one target-specific variable. Am I right? If not, I am not aware what I am doing wrong. Could you please help me?
Target-specific variables are defined only when building that target and any prerequisites of that target. You can't use target-specific variables arbitrarily throughout the makefile (as it sounds like you're trying to do with ifeq). For that, you may want to look at $(MAKECMDGOALS). I don't believe there is any limit on the number of target-specific variables, certainly not a limit of one.
Needing either target-specific variables or $(MAKECMDGOALS) may be a warning that you're trying to do coerce make into doing something it wasn't meant to do.
It's not clear to me whether you want to build three versions (debug/test/release with a single compiler for each one), or six versions. Assuming three, here is a unix-y Makefile to build with different compilers and CFLAGS depending on the target. However, note that this could just as easily be coded with RELEASE_CFLAGS, RELEASE_CC, DEBUG_CFLAGS, etc... variables.
all: release debug test
release: CC=gcc
release: CFLAGS=
debug: CC=gcc
debug: CFLAGS=-g
test: CC=cc
test: CFLAGS=-Wall
.PHONY: release debug test
release: release/exe
debug: debug/exe
test: test/exe
OBJECTS := test.o
release/%.o: %.c
$(CC) $(CLFAGS) -c -o $# $<
debug/%.o: %.c
$(CC) $(CLFAGS) -c -o $# $<
test/%.o: %.c
$(CC) $(CLFAGS) -c -o $# $<
release/exe: $(OBJECTS:%=release/%)
$(CC) $(CFLAGS) -o $# $^
debug/exe: $(OBJECTS:%=debug/%)
$(CC) $(CFLAGS) -o $# $^
test/exe: $(OBJECTS:%=test/%)
$(CC) $(CFLAGS) -o $# $^