How I strip path of source file while writing a compilation rule in makefile? - makefile

In short: I want to compile sources from different directories, and put object files into current directory.
For example, I have files:
test.c
../../lib1/boot.c
../../lib2/startup.c
../common/utils.c
(also few files .s (assembly) and .cpp, but I hope this is not important).
All of their object-files I want to be in the current directory:
test.o
boot.o
startup.o
utils.o
And I can't figure out how to write such rule in my makefile.
For example,
%o.: %.c
does not work now because make can't find a rule to build boot.o from ../../lib1/boot.c, it can only find rule to build ../../lib1/boot.o from ../../lib1/boot.c.
I tried to use this:
%o.: %.c
(my compilation line, for example "gcc -c $^ -o $#")
%o.: ../../lib1/%.c
(my compilation line)
%o.: ../../lib2/%.c
(my compilation line)
%o.: ../common/%.c
(my compilation line)
and it works. But obviously this is not generic enough, and in addition, some user came to me today and said that his application has also some ../../some_other_lib/common_things.c, hence my makefile failed. I looked through our project, and found many such cases with a lot of different directories involved. With my approach, I'll have to write a separate rule for each such directory, with identical compilation line. This does not seem good to me.
So my question is: how to make some generic compilation rule that puts (and checks) object files in current directory, while operating with sources in different directories?
Thank you.

The directories can be extracted from the CSRC variable with $(dir ...) and this list can then be used in the vpath directive.
vpath %.c $(sort $(dir $(CSRC)))
vpath %.s $(sort $(dir $(SSRC)))
vpath %.cpp $(sort $(dir $(CPPSRC)))
(I've thrown in the sort function to remove duplicates, but that's not absolutely necessary.)
Now the rules can be kept simple and make will search the source files in the list of directories.
$(COBJ) := $(notdir $(CSRC))
$(SOBJ) := $(notdir $(SSRC))
$(CPPOBJ) := $(notdir $(CPPSRC))
.PHONY: all
all: $(EXECUTABLE)
$(EXECUTABLE): $(COBJ) $(SOBJ) $(CPPOBJ)
....
$(COBJ): %.o: %.c
...
$(SOBJ): %.o: %.s
...
$(CPPOBJ): %.o: %.cpp
...

Try to use makefile function notdir as this:
%.o: %.c
gcc -c $< -o $(notdir $#)
$# must be equal to the full path ex: ../../lib2/startup.o ad notdir will trunk it to: startup.o.
With this rule you will be able to compile all your source in the current directory.
Actually, your example is like that:
.
└── common
├── lib1
│   └── boot.c
├── lib2
│   └── startup.c
├── test
│   ├── Makefile
│   └── test.c
└── utils.c
I think i will be better like that:
.
├── common
│   ├── lib1
│   │   ├── Makefile
│   │   ├── obj
│   │   └── src
│   │   └── boot.c
│   ├── lib2
│   │   ├── Makefile
│   │   ├── obj
│   │   └── src
│   │   └── startup.c
│   ├── Makefile
│   ├── obj
│   ├── src
│   │   └── utils.c
│   └── test
│   ├── Makefile
│   ├── obj
│   └── src
│   └── test.c
└── Makefile
For that you need all your Makefiles to call the subdirs Makefiles.
and the src/obj dirs is a separation between your source and objects.
SRC := utils.c
OBJ := $(SRC:%.c=%.o)
NAME := project
SRC_D := src
OBJ_D := obj
SUBDIRS := lib1/ \
lib2/ \
test/
all: $(NAME) $(SUBDIRS)
#for dir in $(SUBDIRS); \
do \
$(MAKE) -C $$dir; \
done
$(NAME): $(OBJ:%.o=$(OBJ_D)/%.o)
$(OBJ_D)/%.o : $(SRC_D)/%.c
gcc -c $< -o $#

OK, took me some time, but finally I found the solution (using some threads on this site by the way):
# Defining compilation rules in a way that object files will be produced in current directory, and not in the directory of source files:
all: <List of my targets>
define my_c_rule
$(subst .c,.o,$(notdir $(1))): $(1)
$(CC) $(CFLAGS) $(CDEFINES) $$^ -o $$#
endef
$(foreach f, $(CSRC), $(eval $(call my_c_rule, $(f))))
$(CSRC) contains list of source files with their paths.
Just need to take into account that if earlier I had something like this:
.c.o:
$(CC) $(CFLAGS) $(CDEFINES) $^ -o $#
all: <List of my targets>
...now I have to put all sentence above the rules which I described in my_c_rule procedure. If I don't do this, make stops after compiling first source file. This is because old "wildcard" rules like .c.o or %.o: %.c do not replace all as a default target (even being written earlier), but non-wildcard rules like boot.o: ../../lib1/boot.c (result of the above macros) do replace the default target in case they are written earlier.

Related

in Makefile remove folders if a filename with the same basename exist

I need to remove in the following case
.
├── a
│   └── index.html
├── a.rst
├── b
│   └── index.html
├── c
│   └── index.html
└── c.rst
folder a and c not b.
I make it work with this Makefile:
$ cat Makefile
.PHONY: clean
HTML_TARGETS:= $(patsubst %.rst,%.html,$(wildcard *.rst))
clean: $(HTML_TARGETS)
%.html: %.rst
#echo rm $(basename $# .html)
$
$ make
rm a
rm c
$
Is there a better way to write it ? (the patsubst use an unneeded .html sub)
What I mean is why don't you just do something like:
.PHONY: clean
HTML_DIRS := $(patsubst %/,%,$(dir $(wildcard */*.html)))
RST_FILES := $(basename $(wildcard *.rst))
clean:
echo rm -r $(filter $(RST_FILES),$(HTML_DIRS))

GNU Make: chdir make process itself

Is it possible to use a makefile that directs the make process itself to chdir? I want to write a makefile that expects to be executed from the build directory.
Suppose I have a project directory structure that looks like this
project/
├── Makefile
├── include
│   └── Foo.h
├── src
│   └── Foo.cpp
└── test
└── FooTest.cpp
and the first thing the make directory does is make a build directory.
project/
├── Makefile
├── _build
├── include
│   └── Foo.h
├── src
│   └── Foo.cpp
└── test
└── FooTest.cpp
Is it possible to direct the makefile to chdir into _build to simplify my rules?
I want to be able to write (for example)
foo : Foo.o
$(LD) $^ -o $# $(LDFLAGS)
rather than
_build/foo : _build/Foo.o
$(LD) $^ -o $# $(LDFLAGS)
I know I can add the build directory to the VPATH in order to affect path resolution, but it seems cleaner to just chdir Make itself. Is there a way to do this (preferably without using guile)?
You can make a simple Makefile that forwards everything:
.DEFAULT_GOAL := all
.PHONY: ${MAKECMDGOALS}
$(filter-out all,${MAKECMDGOALS}) all: .forward-all ; #:
.forward-all:
${MAKE} -C build ${MAKECMDGOALS}
# Never try to remake this makefile.
${MAKEFILE_LIST}: ;
.SUFFIXES:
GNU Make is not capable of doing this, but NetBSD's bmake can do exactly this.
Suppose we have a project with the following structure:
.
├── foo.c
├── makefile
└── obj/
foo.c is a simple C program that depends only on the standard library.
/* foo.c */
#include <stdio.h>
int main() {
printf("%s\n", "hi there");
}
The makefile uses the common subset of GNU Make and bmake. In general, sticking to the common subset is tedious and not worth doing, this is just for the sake of example.
default: foo
.c.o:
$(CC) -c -o $# $<
foo : foo.o
$(CC) -o $# foo.o
Running bmake produces the following output
$ bmake
cc -c -o foo.o /tmp/make-example/foo.c
cc -o foo foo.o
and produces the following directory structure
.
├── foo.c
├── makefile
└── obj/
├── foo
└── foo.o
It's clear from inspecting the output that bmake almost immediately chdired into the obj directory. Paths to outputs in the obj directory are relative and paths inside the source directory are absolute.

makefile compile changed latex files in subdirectory

I am trying to create a makefile to compile LaTeX files in subdirectories. The desired directory structure should look like this, except instead of simply a, b, and c, there can be any number of subdirectories under the latex folder.
├── latex
│   ├── a
│   │   ├── output
│   │   │   └── stuff.pdf
│   │   └── stuff.tex
│   ├── b
│   │   ├── blah.tex
│   │   └── output
│   │   └── blah.pdf
│   └── c
│   ├── asdf.tex
│   └── output
│   └── asdf.pdf
└── makefile
I want to do this with only one makefile in the latex directory that will automatically compile the tex files in every subdirectory.
My current makefile looks like this:
TEX_COMMAND = pdflatex
TEX_FILES = $(wildcard **/*.tex)
OUTPUT_DIRECTORIES = $(addsuffix output/,$(wildcard */))
PDF_FILES = $(join $(dir $(TEX_FILES)),$(addprefix output/,$(notdir $(TEX_FILES:tex=pdf))))
all: mkdir $(PDF_FILES)
mkdir:
#mkdir -p $(OUTPUT_DIRECTORIES)
$(PDF_FILES): $(TEX_FILES)
#$(TEX_COMMAND) -file-line-error -halt-on-error -output-directory $(dir $#) -aux_directory=$(dir $#) $(subst output/,$(notdir $(#:pdf=tex)),$(dir $#))
#$(TEX_COMMAND) -file-line-error -halt-on-error -output-directory $(dir $#) -aux_directory=$(dir $#) $(subst output/,$(notdir $(#:pdf=tex)),$(dir $#))
clean:
#rm -rf $(OUTPUT_DIRECTORIES)
This will correctly generate the proper pdf, aux, log, toc, etc. files in the output directory in each subdirectory. However, if I change one tex file, then make will cause everything to be recompiled.
I've already looked at many other similar questions. For other questions, the number of subdirectories is known, so you can hardcode them into the makefile. For this situation, the number of subdirectories in the latex folder is constantly changing and being added to, etc, which is why I'm using the wildcard to grab all the tex files. I would prefer not having to create a makefile for each subdirectory and using recursive make.
One of the fundamental shortcomings of Make is its crude handling of wildcards.
In this case, you can use secondary expansion to write a pattern rule that will do what you want:
all: mkdir $(PDF_FILES)
.SECONDEXPANSION:
%.pdf: $$(subst /output/,/, $$(subst .pdf,.tex, $$#))
#echo buiding $# from $<

How can I use the make target as a variable in my makefile?

I'm trying to set up a simple makefile for a project, where I have 10 subproject. Each of the sub projects are in a directory named 1, 2, 3 ... 10. Within each of those directories, I have a single *.c file. I have figured out how to compile all of my *.c files, but I can't figure out how to use the make target to only compile one particular file. Here's what I have so far:
all:
some code
$(#): $(#).c
gcc -o $(#)/$(#) $(#)/$(#).c
If it helps, this is my general directory structure:
├── 1
│   └── 1.c
├── 2
│   └── 2.c
├── 3
│   └── 3.c
└── makefile
BINARIES = 1/1 2/2 3/3...
all: $(BINARIES)
some code
$(BINARIES): %: %.c
gcc -o $(#) $<
Is probably close from what you are looking for. The $(BINARIES): %: %.c is a static pattern rule. To understand its behaviour you can read section 4.12 Static Pattern Rules of the GNU make manual.

Using GNU Make with subdirectories

I was wondering what different approaches of using Make in a project with subdirectories exist, and what are their advantages/drawbacks, but could never see a good summary or cookbook.
I have seen in my researches mainly the "recursive" and "single makefile" approaches, but are there others ?
I also assume that there is not only one "recursive" or "single makefile" approaches but several, so could somebody sum it up ?
For my particular case, I would like a directory architecture looking like this:
.
├── build
│   ├── *.d
│   ├── *.o
| ├── subdir1
| │ ├── *.d
| │ └── *.o
| └── subdir2
| ├── *.d
| ├── *.o
| └── subdir3
| ├── *.d
| └── *.o
├── include
│   ├── *.h
│   └── *.h
├── Makefile
└── src
├── *.c
├── *.h
├── subdir1
│   ├── *.c
│   └── *.h
└── subdir2
├── *.c
├── *.h
└── subdir3
├── *.c
└── *.h
Which solution should I choose ? Possibly one which would allow source files with the same name ?
Your project setup is really basic, so should be your Makefile:
SRC_DIR := src
BLD_DIR := build
SRC := $(shell find $(SRC_DIR) -name "*.c")
OBJ := $(SRC:$(SRC_DIR)/%.c=$(BLD_DIR)/%.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP # enable auto-dependency generation
CFLAGS := -Wall -W -pedantic
.PHONY: all clean
all: $(OBJ)
clean:
$(RM) -r $(BLD_DIR)
.SECONDEXPANSION:
$(BLD_DIR)/%.o: $(SRC_DIR)/%.c | $$(#D)/ # First check that the destination directory exists
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
%/:
mkdir -p $* # -p flag necessary for recursive directory creation
ifeq "$(MAKECMDGOALS)" ""
-include $(DEP)
endif
The idea here is to list source files recursively using the find command, to supply make with the appropriate pattern rule to compile in the right place and pass the right preprocessor file to your compiler to enable auto-dependency generation.
Tested with GNU Make 4.1 under Windows 8.1 with the GIT Bash shell and the following directory structure:
.
├── Makefile
└── src
├── test.c
├── test1.c
└── subdir1
└── test.c
After reading Recursive Make Considered Harmful, I figured a quite simple and modular way to achieve this, by having files in all subdirectories that would include each other and be included in the main makefile:
CXX := gcc
SRCDIR := src
OBJDIR := build
# These lines are needed to set immediate evaluation for
# these variables, instead of deferred evaluation which is unsuitable.
SRCS :=
SUBDIRS :=
CFLAGS :=
LDFLAGS :=
include $(SRCDIR)/module.mk
OBJS := $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
SRCS := $(addprefix $(SRCDIR)/, $(SRCS))
DEPS := $(OBJS:.o=.d)
TMPS := $(OBJS) $(OBJS:.o=.d)
CFLAGS += -MD
debug: CFLAGS += -g -g3 -ggdb
CFLAGS += $(addprefix -I./$(SRCDIR)/, $(SUBDIRS))
LDFLAGS += -lsomelib
debug: LDFLAGS += -g -g3 -ggdb
NAME := yolo
all: $(NAME)
debug: re
-include $(DEPS)
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(NAME): $(OBJS)
#$(CXX) $(OBJS) -o $(NAME) $(LDFLAGS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
#mkdir -p $(OBJDIR)
#for dir in $(SUBDIRS); \
do \
mkdir -p $(OBJDIR)/$$dir; \
done
clean:
rm -rf $(TMPS)
fclean: clean
rm -rf $(NAME)
rm -rf $(OBJDIR)
re: fclean all
.PHONY: all clean fclean re
And in every subdirectory, a module.mk file (I could have named it anything, but this seemde cool).
For src:
SRCS := main.c file1.c file2.c
SUBDIRS += subdir1 subdir2
include $(SRCDIR)/subdir1/module.mk
include $(SRCDIR)/subdir2/module.mk
For a level 1 subdirectory:
THIS_DIR_L0 := subdir1
MOD_SRC := file3.c file4.c
SRCS += $(addprefix $(THIS_DIR_L0)/, $(MOD_SRC))
SUBDIRS += $(THIS_DIR_L0)/subdir3
include $(SRCDIR)/$(THIS_DIR_L0)/subdir3/module.mk
And for a level 2 subdir (one deeper):
THIS_DIR_L1 := subdir3
MOD_SRC := file5.c file6.c
SRCS += $(addprefix $(THIS_DIR_L0)/$(THIS_DIR_L1)/, $(MOD_SRC))
And so on...
This is quite simple to set up, I find it very modular and it does not use recursive makefiles. It would not be complicated to make librairies and stuff inside your directory structure either.
Anybody having a better idea please tell me.

Resources