I have a makefile like this:
default: exe
%.obj: %.src
# dummy compiler
#echo link $< to $#
cat $< > $#
exe: main.obj foo.obj bar.obj
# dummy linker
#echo link $^ to $#
cat $^ > $#
main.obj: main.src
foo.obj: /some/dir/1/foo.src
bar.obj: /some/dir/2/bar.src
Make can't compile foo.obj and bar.obj (and 20+ other objects), because it does not use the "%.obj: %.src" rule. The directories of foo.obj and foo.src resp. bar.obj and bar.src do not match, so the rule does not match.
Is there a way to specify a rule that ignores the directory part of the filenames?
Update:
To make that Makefile work, I copied the compiler lines from the pattern rule to the foo.obj and bar.obj rules (and the 20+ other object rules). That's anything but clean and maintainable. Essentially, I need a pattern rule that ignores the source and object directories when comparing.
I know of no such features (excepted macros, you could arrange for them to generate the makefile fragments you are writing manually). But GNU Make has a vpath feature which allows to specify a path where to look for files of a given extension and which interact with the automatic variables to make something close to what you want.
Your Makefile can be then written as:
default: exe
vpath %.src some/dir/1:some/dir/2
%.obj: %.src
# dummy compiler
#echo compiling $< to $#
cat $< > $#
exe: main.obj foo.obj bar.obj
# dummy linker
#echo linking $^ to $#
cat $^ > $#
Note that this is not exactly what you want: if there is a bar.src in both some/dir/1 and some/dir/2, the one from some/dir/1 will be used.
You can make a variable of all .src files in all subdirectories with $(shell find . -name '*.src'). Here's an example:
OBJS := $(shell find . -name '*.src')
default: exe
%.obj: %.src
#echo link $< to $#
cat $< > $#
exe: $(OBJS)
#echo link $^ to $#
cat $^ > $#
The macro way of doing this would be as follows:
define mymacro
$1: $2
#echo compiling $$< to $$#
cat $$< > $$#
endef
$(eval $(call mymacro,foo.obj,/some/dir/1/foo.src))
$(eval $(call mymacro,bar.obj,/some/dir/2/bar.src))
But be aware that macros make the makefile less maintainable (as it's harder to read, and introduces some sharp sticks inexperienced users might trip on). It also works on GNU make, but may fail on some other make systems.
I have written a build system which uses gmtt and which relies on explicit source elicitation. At the core is a beefed up version of wildcard named wildcard-rec which supports recursive descent akin to ** in other extended wildcard matchers (like git) - maybe it fits your taste and use case:
include gmtt.mk
default: exe
SOURCE_LOCATOR := $(call wildcard-rec,main.src some/dir/**/3/*.src some/**/1/foo.src some/dir/2/bar.src)
$(info Compiling these sources: $(SOURCE_LOCATOR))
OBJECTS := $(addsuffix .obj,$(basename $(notdir $(SOURCE_LOCATOR))))
$(info Building these objects: $(OBJECTS))
# Generate the source prerequisite for each object
TGT-PREREQ := $(join $(addsuffix :,$(OBJECTS)),$(SOURCE_LOCATOR))
# Introduce them as targets via eval:
$(foreach tp,$(TGT-PREREQ),$(info $(tp))$(eval $(tp)))
$(OBJECTS):
#echo compile $< to $#
exe: $(OBJECTS)
#echo link $^ to $#
Test:
Compiling these sources: main.src some/dir/foo/3/a.src some/dir/foo/3/b.src some/dir/bar/1/foo.src some/dir/2/bar.src
Building these objects: main.obj a.obj b.obj foo.obj bar.obj
main.obj:main.src
a.obj:some/dir/foo/3/a.src
b.obj:some/dir/foo/3/b.src
foo.obj:some/dir/bar/1/foo.src
bar.obj:some/dir/2/bar.src
compile main.src to main.obj
compile some/dir/foo/3/a.src to a.obj
compile some/dir/foo/3/b.src to b.obj
compile some/dir/bar/1/foo.src to foo.obj
compile some/dir/2/bar.src to bar.obj
link main.obj a.obj b.obj foo.obj bar.obj to exe
Hi I am trying to write a generic (basic) Makefile to compile basic, practice c programs.
I have a src directory that I am practicing c programming in. My directory structure looks something like this:
practice/src/ex1.c
ex2.c
ex3.c
practice/build
my Makefile looks like this:
blddir = ./build
srcdir = ./src
# RM="find $(blddir) -maxdepth 1 -executable -type f -name 'ex*' -delete"
CFLAGS=-Wall -g
$(csrc): %.c
$(CC) -o $(blddir)/$# $(srcdir)/$^ # all prereqs
clean:
find $(blddir) -maxdepth 1 -executable -type f -name 'ex*' -delete
When I run: make ex6, I am greeted with : make: *** No rule to make target 'ex6'. Stop.
When I run: make -p ex6 | less
...and search for ex6 I see:
.DEFAULT_GOAL := src/ex6.c
src/ex6.c: %.c
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (from 'Makefile', line 15):
$(CC) -o $(blddir)/$# $(srcdir)/$^ # all prereqs
What am I missing?
Thanks!
...more reading more testing, new(er) Makefile:
blddir = ./build
srcdir = ./src
CFLAGS=-Wall -g
% : $(srcdir)/%.c
$(CC) -o $(blddir)/$# $^ # all prereqs
make ex6
...and it works
I'm trying to create a makefile that compiles all the cpp files in the src directory whenever they change, or whenever a header that they include changes. My problem is that when a file includes enough files to where gcc wraps the rule to a new line, as per the documentation for using the -M options, make treats the line break as another space and the rule tries to create an empty dependency.
For example, running the makefile with a file in the src directory called source.cpp containing:
#include "header1.hpp"
#include "header2.hpp"
#include "header3.hpp"
#include "header4.hpp"
#include "header5.hpp"
will output something along the lines of:
Missing file header1.hpp
Missing file header2.hpp
Missing file header3.hpp
Missing file
Missing file header4.hpp
Missing file header5.hpp
Compiling src/source.cpp...
This is my makefile right now:
SRCDIR = src
OBJDIR = obj
SRCFLS = $(shell find $(SRCDIR) -name *.cpp)
OBJFLS = $(call getobj,$(SRCFLS))
CXXFLAGS = -c -I .
define \n
endef
define \t
endef
define getobj
$(subst $(SRCDIR)/,$(OBJDIR)/,$(subst .cpp,.o,$(1)))
endef
define getrule
$(shell $(CXX) -MM -MG -MT $(call getobj,$(1)) $(1))
endef
default : $(OBJFLS);
% :
#echo Missing file $#
$(eval $(foreach FLE,$(SRCFLS),\
\
$(call getrule,$(FLE))$(\n)$(\t)\
#echo Compiling $$<...$(\n)$(\t)\
#mkdir $$(#D) -p$(\n)$(\t)\
#-$(CXX) $(CXXFLAGS) $$< -o $$#$(\n)\
\
))
Sorry if the question is confusing, I'm willing to clear up any details needed.
I would like to build a C-project for my microcontroller with the GNU make tool. I would like to do it in a clean way, such that my source code is not cluttered with object files and other stuff after the build. So imagine that I have a project folder, called "myProject" with two folders in it:
- myProject
|
|---+ source
|
'---+ build
The build folder only contains a makefile. The figure below shows what should happen when I run the GNU make tool:
So GNU make should create an object file for each .c source file it can find in the source folder. The object files should be structured in a directory tree that is similar to the structure in the source folder.
GNU make should also make a .d dependency file (in fact, a dependency file is some sort of makefile itself) for each .c source file. The dependency file is described in the GNU make manual chapter 4.14 "Generating Prerequisites Automatically":
For each source file name.c there is a makefile name.d which lists
what files the object file name.o depends on.
From the following Stackoverflow question About the GNU make dependency files *.d, I learned that adding the options -MMD and -MP to the CFLAGS of the GNU gcc compiler can help to automate that.
So now comes the question. Has anyone a sample makefile that performs such out-of-source build? Or some good advices on how to get started?
I'm pretty sure that most people who have written such a makefile, are Linux-people. But the microcontroller project should build also on a Windows machine. Anyway, even if your makefile is Linux-only, it provides a good starting point ;-)
PS: I would like to avoid extra tools like CMake, Autotools, or anything that has to do with an IDE. Just pure GNU make.
I would be very grateful :-)
Updating the dependency files
Please have a look at this question: What is the exact chain of events when GNU make updates the .d files?
Here's the Makefile I've added to the documentation (currently in review so I'll post it here) :
# Set project directory one level above the Makefile directory. $(CURDIR) is a GNU make variable containing the path to the current working directory
PROJDIR := $(realpath $(CURDIR)/..)
SOURCEDIR := $(PROJDIR)/Sources
BUILDDIR := $(PROJDIR)/Build
# Name of the final executable
TARGET = myApp.exe
# Decide whether the commands will be shown or not
VERBOSE = TRUE
# Create the list of directories
DIRS = Folder0 Folder1 Folder2
SOURCEDIRS = $(foreach dir, $(DIRS), $(addprefix $(SOURCEDIR)/, $(dir)))
TARGETDIRS = $(foreach dir, $(DIRS), $(addprefix $(BUILDDIR)/, $(dir)))
# Generate the GCC includes parameters by adding -I before each source folder
INCLUDES = $(foreach dir, $(SOURCEDIRS), $(addprefix -I, $(dir)))
# Add this list to VPATH, the place make will look for the source files
VPATH = $(SOURCEDIRS)
# Create a list of *.c sources in DIRS
SOURCES = $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.c))
# Define objects for all sources
OBJS := $(subst $(SOURCEDIR),$(BUILDDIR),$(SOURCES:.c=.o))
# Define dependencies files for all objects
DEPS = $(OBJS:.o=.d)
# Name the compiler
CC = gcc
# OS specific part
ifeq ($(OS),Windows_NT)
RM = del /F /Q
RMDIR = -RMDIR /S /Q
MKDIR = -mkdir
ERRIGNORE = 2>NUL || true
SEP=\\
else
RM = rm -rf
RMDIR = rm -rf
MKDIR = mkdir -p
ERRIGNORE = 2>/dev/null
SEP=/
endif
# Remove space after separator
PSEP = $(strip $(SEP))
# Hide or not the calls depending of VERBOSE
ifeq ($(VERBOSE),TRUE)
HIDE =
else
HIDE = #
endif
# Define the function that will generate each rule
define generateRules
$(1)/%.o: %.c
#echo Building $$#
$(HIDE)$(CC) -c $$(INCLUDES) -o $$(subst /,$$(PSEP),$$#) $$(subst /,$$(PSEP),$$<) -MMD
endef
# Indicate to make which targets are not files
.PHONY: all clean directories
all: directories $(TARGET)
$(TARGET): $(OBJS)
$(HIDE)echo Linking $#
$(HIDE)$(CC) $(OBJS) -o $(TARGET)
# Include dependencies
-include $(DEPS)
# Generate rules
$(foreach targetdir, $(TARGETDIRS), $(eval $(call generateRules, $(targetdir))))
directories:
$(HIDE)$(MKDIR) $(subst /,$(PSEP),$(TARGETDIRS)) $(ERRIGNORE)
# Remove all objects, dependencies and executable files generated during the build
clean:
$(HIDE)$(RMDIR) $(subst /,$(PSEP),$(TARGETDIRS)) $(ERRIGNORE)
$(HIDE)$(RM) $(TARGET) $(ERRIGNORE)
#echo Cleaning done !
Main features
Automatic detection of C sources in specified folders
Multiple source folders
Multiple corresponding target folders for object and dependency files
Automatic rule generation for each target folder
Creation of target folders when they don't exist
Dependency management with gcc : Build only what is necessary
Works on Unix and DOS systems
Written for GNU Make
How to use this Makefile
To adapt this Makefile to your project you have to :
Change the TARGET variable to match your target name
Change the name of the Sources and Build folders in SOURCEDIR and BUILDDIR
Change the verbosity level of the Makefile in the Makefile itself or in make call (make all VERBOSE=FALSE)
Change the name of the folders in DIRS to match your sources and build folders
If required, change the compiler and the flags
In this Makefile Folder0, Folder1 and Folder2 are the equivalent to your FolderA, FolderB and FolderC.
Note that I have not had the opportunity to test it on a Unix system at the moment but it works correctly on Windows.
Explanation of a few tricky parts :
Ignoring Windows mkdir errors
ERRIGNORE = 2>NUL || true
This has two effects :
The first one, 2>NUL is to redirect the error output to NUL, so as it does not comes in the console.
The second one, || true prevents the command from rising the error level. This is Windows stuff unrelated with the Makefile, it's here because Windows' mkdir command rises the error level if we try to create an already-existing folder, whereas we don't really care, if it does exist that's fine. The common solution is to use the if not exist structure, but that's not UNIX-compatible so even if it's tricky, I consider my solution more clear.
Creation of OBJS containing all object files with their correct path
OBJS := $(subst $(SOURCEDIR),$(BUILDDIR),$(SOURCES:.c=.o))
Here we want OBJS to contain all the object files with their paths, and we already have SOURCES which contains all the source files with their paths.
$(SOURCES:.c=.o) changes *.c in *.o for all sources, but the path is still the one of the sources.
$(subst $(SOURCEDIR),$(BUILDDIR), ...) will simply subtract the whole source path with the build path, so we finally have a variable that contains the .o files with their paths.
Dealing with Windows and Unix-style path separators
SEP=\\
SEP = /
PSEP = $(strip $(SEP))
This only exist to allow the Makefile to work on Unix and Windows, since Windows uses backslashes in path whereas everyone else uses slashes.
SEP=\\ Here the double backslash is used to escape the backslash character, which make usually treats as an "ignore newline character" to allow writing on multiple lines.
PSEP = $(strip $(SEP)) This will remove the space char of the SEP variable, which has been added automatically.
Automatic generation of rules for each target folder
define generateRules
$(1)/%.o: %.c
#echo Building $$#
$(HIDE)$(CC) -c $$(INCLUDES) -o $$(subst /,$$(PSEP),$$#) $$(subst /,$$(PSEP),$$<) -MMD
endef
That's maybe the trick that is the most related with your usecase. It's a rule template that can be generated with $(eval $(call generateRules, param)) where param is what you can find in the template as $(1).
This will basically fill the Makefile with rules like this for each target folder :
path/to/target/%.o: %.c
#echo Building $#
$(HIDE)$(CC) -c $(INCLUDES) -o $(subst /,$(PSEP),$#) $(subst /,$(PSEP),$<) -MMD
This fairly minimal makefile should do the trick:
VPATH = ../source
OBJS = FolderA/fileA1.o FolderA/fileA2.o FolderB/fileB1.o
CPPFLAGS = -MMD -MP
all: init myProgram
myProgram: $(OBJS)
$(CC) $(LDFLAGS) -o $# $(OBJS) $(LDLIBS)
.PHONY: all init
init:
mkdir -p FolderA
mkdir -p FolderB
-include $(OBJS:%.o=%.d)
The main tricky part is ensuring that FolderA and FolderB exist in the build directory bfore trying to run the compiler that will write into them. The above code will work sequential for builds, but might fail with -j2 the first time it is run, as the compiler in one thread might try to open an output file before the other thread creates the directory. Its also somewhat unclean. Usually with GNU tools you have a configure script that will create those directories (and the makefile) for you before you even try to run make. autoconf and automake can build that for you.
An alternate way that should work for parallel builds would be to redefine the standard rule for compiling C files:
VPATH = ../source
OBJS = FolderA/fileA1.o FolderA/fileA2.o FolderB/fileB1.o
CPPFLAGS = -MMD -MP
myProgram: $(OBJS)
$(CC) $(LDFLAGS) -o $# $(OBJS) $(LDLIBS)
%.o: %.c
mkdir -p $(dir $#)
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
-include $(OBJS:%.o=%.d)
Which has the disadvantage that you'll also need to redefine the builtin rules for any other kind of sourcefile you want to compile
Here's a basic one I use all the time, it's pretty much a skeleton as it is but works perfectly fine for simple projects. For more complex projects it certainly needs to be adapted, but I always use this one as a starting point.
APP=app
SRC_DIR=src
INC_DIR=inc
OBJ_DIR=obj
BIN_DIR=bin
CC=gcc
LD=gcc
CFLAGS=-O2 -c -Wall -pedantic -ansi
LFLGAS=
DFLAGS=-g3 -O0 -DDEBUG
INCFLAGS=-I$(INC_DIR)
SOURCES=$(wildcard $(SRC_DIR)/*.c)
HEADERS=$(wildcard $(INC_DIR)/*.h)
OBJECTS=$(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
DEPENDS=$(OBJ_DIR)/.depends
.PHONY: all
all: $(BIN_DIR)/$(APP)
.PHONY: debug
debug: CFLAGS+=$(DFLAGS)
debug: all
$(BIN_DIR)/$(APP): $(OBJECTS) | $(BIN_DIR)
$(LD) $(LFLGAS) -o $# $^
$(OBJ_DIR)/%.o: | $(OBJ_DIR)
$(CC) $(CFLAGS) $(INCFLAGS) -o $# $<
$(DEPENDS): $(SOURCES) | $(OBJ_DIR)
$(CC) $(INCFLAGS) -MM $(SOURCES) | sed -e 's!^!$(OBJ_DIR)/!' >$#
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif
$(BIN_DIR):
mkdir -p $#
$(OBJ_DIR):
mkdir -p $#
.PHONY: clean
clean:
rm -rf $(BIN_DIR) $(OBJ_DIR)
I would avoid manipulating Makefile directly, and use CMake instead.
Just describe your source files in CMakeLists.txt, as below:
Create file MyProject/source/CMakeLists.txt containing;
project(myProject)
add_executable(myExec FolderA/fileA1.c FolderA/fileA2.c FolderB/fileB1.c)
Under MyProject/build, run
cmake ../source/
You'll get a Makefile now. To build, under the same build/ directory,
make
You may also want to switch to a lightning fast build tool, ninja, simply by adding a switch as following.
cmake -GNinja ..
ninja
I believe I have a problem with the cpp preprocessor used by my Makefile (which compiles Fortran code). I have recently changed operating systems, and now compilation does not work, and I do not know enough about Makefiles or preprocessors to fix it (the Makefile was given to me many years ago).
I have recently updated from Fedora 10 to Fedora 19 (yes, should've done so earlier). After copying my code to the new system, and running gmake, I found out I was having problems with compilation. From what I have understood, what is supposed to happen is that my .F files are preprocessed and written as .f files. Apparently, the cpp preprocessor is now adding some sort of GNU disclaimer ("/* Copyright (C) 1991-2012 Free Software Foundation, Inc. This file is part of the GNU C Library.... "), which the compiler (f77) does not like. In principle, I could erase this text from each of the generated .f files, but seriously, this takes too much time.
I really don't know what is the cause of the problem. I'd like to tell cpp not output this text, or f77 to ignore it, but haven't found any flag that manages this. Considered re-writing the Makefile (using more modern compilers, for instance), but I'm a bit hopeless on this at the moment. Hopefully someone can help me with this. I'm copying the Makefile below, as well as the output.
Thanks in advance.
Makefile
# Make sure the SHELL is right
SHELL = /bin/sh
MAKE = gmake
# Define several root directories
LEP_ROOT := /home/stilgar/SUSY/NeutrinoModel2
CERN_ROOT := /usr/lib64/cernlib/2006
INCLUDES := $(LEP_ROOT)/include
INCLUDES := $(strip $(INCLUDES))
incpath := $(subst $(space),:,$(INCLUDES))
vpath %.inc $(incpath)
# Define tree
BIN_DIR := $(LEP_ROOT)/bin
# Define source directory
SRCDIR := $(LEP_ROOT)/src
# Libraries
libs := $(CERN_ROOT)/lib
libs := $(addprefix -L, $(libs))
libs += `cernlib packlib,mathlib,packlib,kernlib`
#Source files
#Main Program
src_files += $(wildcard $(SRCDIR)/main_lfv.F)
#SM Parameters
src_files += $(wildcard $(SRCDIR)/param_basic.F)
src_files += $(wildcard $(SRCDIR)/numajmass.F)
#SUSY Spectrum
src_files += $(wildcard $(SRCDIR)/texture2.F)
src_files += $(wildcard $(SRCDIR)/minserts.F)
#SUSY Flavour
src_files += $(wildcard $(SRCDIR)/gmin2.F)
src_files += $(wildcard $(SRCDIR)/lfv.F)
#Bounds
src_files += $(wildcard $(SRCDIR)/experiment.F)
src_files += $(wildcard $(SRCDIR)/directsearch.F)
#Loop Functions
src_files += $(wildcard $(SRCDIR)/fedm.F)
src_files += $(wildcard $(SRCDIR)/gedm.F)
#Mathematical Tools
src_files += $(wildcard $(SRCDIR)/biunitary3.F)
main_obj_files += $(src_files:%.F=%.o)
main_ofiles += $(notdir $(main_obj_files))
main_files += $(src_files:%.F=%.f)
depend += $(main_obj_files:.o=.d)
# Name of the executable to be created
exectry := $(BIN_DIR)/RunStuff
# Define flags
FC = f77
#FC = gfortran
#FC = g95
FFLAGS += -c
FFLAGS += $(addprefix -I, $(INCLUDES))
# Define cpp options
CPP = cpp
CPPFLAGS += -C -P -E
CPPFLAGS += $(addprefix -I, $(INCLUDES))
.PHONY : all clean cleanall help
.PHONY : sclean
all: $(exectry)
$(exectry): $(main_obj_files) $(main_files)
#echo '==================================================='
#echo ' Building executable ' $(exectry)
#echo ' '
#-rm -f $#
$(FC) -o $# $(main_obj_files) $(LFLAGS) $(libs)
#echo ' Done '
#echo '==================================================='
clean : sclean
#echo
#echo Cleaning up *.o *~ core
#echo
#-rm -f *.o core
#echo done.
sclean :
#find . -name "*.bak" -exec rm -f '{}' ';'
#find . -name "*~" -exec rm -f '{}' ';'
#find . -name "#*#" -exec rm -f '{}' ';'
cleanall :
#echo '**********************************************************'
#echo ' Clean all : '
#find . -name "*.bak" -exec rm -f '{}' ';'
#find . -name "*~" -exec rm -f '{}' ';'
#find . -name "*.log" -exec rm -f '{}' ';'
#find . -name "*.out" -exec rm -f '{}' ';'
#find . -name "core" -exec rm -f '{}' ';'
#find . -name "#*#" -exec rm -f '{}' ';'
#-rm -f *.o *.d
#echo done.
#echo '**********************************************************'
help:
#echo
#echo ' The possible options are :'
#echo ' ======================== '
#echo
#echo ' gmake -- build batch executable'
#echo ' gmake sclean -- simple clean up '
#echo ' gmake clean -- clean up a bit more '
#echo ' gmake cleanall -- clean everything'
#echo
%.f:%.F
#echo Preprocessing ... $<
#$(CPP) $(CPPFLAGS) $< > $#
%.o:%.f
#echo Compiling ... $<
#$(FC) $(FFLAGS) -o $# $<
%.d:%.F
#touch $#
#echo Updating ... $#
#makedepend -- $(CPPFLAGS) -- $< -f $#
#-rm $#.bak
Output
Preprocessing ... /home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.F
Compiling ... /home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f
/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f:2:
This file is part of the GNU C Library.
^
Non-numeric character at (^) in label field [info -f g77 M LEX]
/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f:4:
The GNU C Library is free software; you can redistribute it and/or
^
Non-numeric character at (^) in label field [info -f g77 M LEX]
/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.f:5:
modify it under the terms of the GNU Lesser General Public
^
Non-numeric character at (^) in label field [info -f g77 M LEX]
(...)
gmake: *** [/home/stilgar/SUSY/NeutrinoModel2/src/main_lfv.o] Error 1
I think the problem is the -C option in the CPPFLAGS variable. The man page for cpp says that this causes the preprocessor to not discard comments. I don't think you want that. Remove that flag.
Another nit: you never want to set the MAKE variable in your makefile.