Makefile: use a target from a project.mk file - makefile

I have a Makefile in the workspace folder. There are individual projects where there are project.mk files.
In the main Makefile, I want to use targets from the individual project.mk files.
all: buildUIProject1 buildUIProject2
Where buildUIProject1 is a target in project.mk
buildUIProject1: $(shell find src -name *)
npm run build
How can I accomplish this?

What you'd do is a recipe for the buildUIProject1 that runs make (recursively) on project.mk. In the main makefile:
buildUIProject1:
$(MAKE) -C project1/folder -f project.mk $#

Related

Makefile: how to avoid specifying all targets manually

I wrote this Makefile:
all: clean basedemo.exe
clean:
rm -f *.exe
%.exe: %.s
vasmm68k_mot -kick1hunks -Fhunkexe -o $# -nosym $<
My goal would be to compile every .s file in the current folder to a separate .exe.
Right now, I have to append the new .exe file name to the line: all: clean basedemo.exe new_file.exe
Is there a way to avoid having to do that?
Thank you
I tried using a wildcard:
all: clean $(wildcard *.exe)
But when I run make all only the clean recipe runs.
$(wildcard *.exe) searchs for existing .exe files, but they do not exist yet when you run make.
What you can do is to find all .s files and substitute their extension to .exe:
FILES_S:=$(wildcard *.s)
FILES_EXE:=$(FILES_S:%.s=%.exe)
all : clean $(FILES_EXE);

Makefile to generate a binary file for each source file

I have the following structure in my project.
/
src/
bin/
Makefile
In src directory there will be multiple src files (each has a main function). I need to write makefile such that when I run
make program1
It should search for program1.c in src folder and compile the executable as program1* in bin folder.
I have came across this question How can Makefile use separate directories for source code and binaries?
But, it seems that I need to manually enter all program names into PROG variable.
I just need to supply binary name with make and it should do the compilation for that respective src file?
Okay, after a bit of experimentation with my Makefile. I finally got the solution for my problem.
Current Build System
CC = gcc
CFLAGS = -g -Wall
SRC = ./src/
BIN = ./bin/
%: $(SRC)%.c
$(CC) $(CFLAGS) $< -o $(BIN)$#
.PHONY: clean
clean:
rm $(BIN)*

Need to run make twice after make clean

All I want to do is gather source files from different source directories into one folder and then do the build of those make files. After a make clean I have to run make command twice to do the build.
So first I run make clean, then i run make, which throws an error saying no -o files found. But when iIrun the make again, the build goes through and generates the build files.
My makefile looks like below
.PHONY: dirs all clean
all: dirs $(OBJ_DIR) $(OBJ_FILES)
"$(CC) -rvn fLib.a $(OBJ_FILES)
# clean build target. Remove all files without reporting errors in case they don't exist.
clean:
#rm -rf fLib.a $(OBJ_DIR)
# Build target for creating flat header file folder for SharedTrackerAPI (FLAT_INC_DIR)
# due to too long paths in Windows 7 build
dirs:
#echo 'Making flat source and header folders.'
#mkdir -p $(OBJ_DIR)
#for f in $(SRC_FILES); do cp $$f $(OBJ_DIR); done
#mkdir -p $(FLAT_INC_DIR)
#OLD_CWD=$(CURDIR)
#cd $(FLAT_INC_DIR)
#find $(STA_RADAR_TRACKER_IFACE) -name '*.h' | xargs -i cp -l {} $(FLAT_INC_DIR)
#cd $(OLD_CWD)
$(OBJ_DIR)/%.o: $(OBJ_DIR)/%.cpp
"$(TASKING_CTC_BIN)"/cctc.exe $(CXXFLAGS) -c -o $# $< $(CC_INCLUDE_PATH)
What am I doing wrong that I have to run make twice after a make clean.
The problem is that although dirs will place the source files in the flat source directory, Make doesn't know that. Before it executes the dirs rule, it has already determined that it knows no way to build the object files.
The quick and dirty solution is to tell Make "trust me, it'll be fine"; one way to do that is to modify the object rule like this:
$(OBJ_DIR)/%.o:
"$(TASKING_CTC_BIN)"/cctc.exe $(CXXFLAGS) -c -o $# $(OBJ_DIR)/$*.cpp $(CC_INCLUDE_PATH)
If you stop there, you will have a working solution.
If you want a more clean, efficient and flexible makefile, you must rethink the approach to finding source files. I see no good reason to use the flat source file approach, but if you really want to use it, here is a good way:
vpath %.cpp $(dir $(SRC_FILES))
$(OBJ_DIR)/%.cpp: %.cpp
#cp $< $#
Now you can get rid of dir and use your unmodified object rule:
$(OBJ_DIR)/%.o: $(OBJ_DIR)/%.cpp
"$(TASKING_CTC_BIN)"/cctc.exe $(CXXFLAGS) -c -o $# $< $(CC_INCLUDE_PATH)
How to handle the header files (FLAT_INC_DIR) is up to you, but I recommend vpath again.

Build make target if contents of directory have changed

I need a Makefile that allows me to enter make foo-program and, if any foo-program/**/*.hs file has changed since last build, build the target (output in foo-program/.stack-work).
Here is my directory tree:
project/
|-bar-other-program/
|-.stack-work/ # Generated output goes here
|-src/
|-BarOtherProgram.hs
|-test/
|-Tests.hs
|-foo-program/
|-.stack-work/ # Generated output goes here
|-src/
|-FooProgram.hs
|-test/
|-Tests.hs
|-notes/ # non-source, so no Make target for this
Here is what I have so far:
# evaluates to 'bar-other-program foo-program'
PROGS := $(shell find * -type f -name '*.hs' | cut -d'/' -f1 | uniq)
.SECONDEXPANSION:
$(PROGS): $$(wildcard $$#/src/*.hs) $$(wildcard $$#/test/*.hs)
# do-build $#
When I run make foo-program, whether the source has changed or not, I get:
make: Nothing to be done for 'foo-program'
UPDATE: My final (non-abstracted) Makefile can be found on GitHub. Note that my solution took a different turn than I intended when I wrote up this question. Looking at that Makefile also might also make it more clear as to my original goal.
I am not quite sure of the the purpose of cut -d'/' there.
But if you just want a list of *.hs files in the current directory (recursively found) and then build a target/executable based on whether they have changed, you can do something like this:
PROGS = $(subst ./,,$(shell find . -type f -name '*.hs'))
DEPS = $(addprefix stackwork/,$(addsuffix .dep,$(basename $(PROGS))))
DIRS = $(dir $(DEPS))
.PHONY: foo-program
foo-program: $(DEPS) $(DIRS)
stackwork/%.dep: %.hs | $(DIRS)
#echo making $#
#touch $#
$(DIRS):
#echo creating dir $#
#mkdir -p $#
clean:
#rm -rf $(DEPS) $(DIRS)
Where:
PROGS is your list of .hs files
DEPS is a list of generated dependency files (empty but date stamps will be used)
DIRS is a list of output directories that need to be created (I guess they don't exist by default since they are output folders?)
foo-program is a rule that you can call (PHONY because at the moment it does not create a real file)
%.dep: %.hs is a rule how to generate a .dep file (this could be a .o .obj or any other file type) which depends on its .hs file equivalent.
$(DIRS): is a rule to create your output directories if needed.
So if the .dep files don't exist, all of the .hs files will be "compiled". If all the .dep files exist and are up to date, then nothing will be compiled. If one or more file is out of date then just those files will be built. Here is the output of running this on my PC with a few test files:
admin#osboxes:~/sandbox$ make
creating dir stackwork/
creating dir stackwork/test/
creating dir stackwork/test/test2/
making stackwork/file.dep
making stackwork/test/file.dep
making stackwork/test/test2/file2.dep
admin#osboxes:~/sandbox$ make
make: Nothing to be done for 'foo-program'.
admin#osboxes:~/sandbox$ touch test/file.hs
admin#osboxes:~/sandbox$ make
making stackwork/test/file.dep
admin#osboxes:~/sandbox$ make
make: Nothing to be done for 'foo-program'.

make wildcard subdirectory targets

I have a "lib" directory in my applications main directory, which contains an arbitrary number of subdirectories, each having its own Makefile.
I would like to have a single Makefile in the main directory, that calls each subdirectory's Makefile. I know this is possible if I manually list the subdirs, but I would like to have it done automatically.
I was thinking of something like the following, but it obviously does not work. Note that I also have clean, test, etc. targets, so % is probably not a good idea at all.
LIBS=lib/*
all: $(LIBS)
%:
(cd $#; $(MAKE))
Any help is appreciated!
The following will work with GNU make:
LIBS=$(wildcard lib/*)
all: $(LIBS)
.PHONY: force
$(LIBS): force
cd $# && pwd
If there might be something other than directories in lib, you could alternatively use:
LIBS=$(shell find lib -type d)
To address the multiple targets issue, you can build special targets for each directory, then strip off the prefix for the sub-build:
LIBS=$(wildcard lib/*)
clean_LIBS=$(addprefix clean_,$(LIBS))
all: $(LIBS)
clean: $(clean_LIBS)
.PHONY: force
$(LIBS): force
echo make -C $#
$(clean_LIBS): force
echo make -C $(patsubst clean_%,%,$#) clean
There is also a way of listing sub-directories with gmake commands only, without using any shell commands:
test:
#echo $(filter %/, $(wildcard lib/*/))
This will list all sub-directories with trailing '/'. To remove it you can use the substitute pattern:
subdirs = $(filter %/, $(wildcard lib/*/))
test:
#echo $(subdirs:%/=%)
Then to actually create rules executing makefiles in each sub-directory you can use a small trick - a phony target in a non-existent directory. I think in this case an example will tell more than any explanation:
FULL_DIRS =$(filter %/, $(wildcard lib/*/))
LIB_DIRS =$(FULL_DIRS:%/=%)
DIRS_CMD =$(foreach subdir, $(LIB_DIRS), make-rule/$(subdir))
make-rule/%:
cd $* && $(MAKE)
all: DIRS_CMD
Basically, target 'all' lists all sub-directories as prerequisites. For example, if LIB_DIRS contained lib/folder1 lib/folder2 then the expansion would look like this:
all: make-rule/lib/folder1 make-rule/lib/folder2
Then 'make', in order to execute rule 'all', tries to match each prerequisite with an existing target. In this case the target is 'make-rule/%:', which uses '$*' to extract the string after 'make-rule/' and uses it as argument in the recipe. For example, the first prerequisite would be matched and expanded like this:
make-rule/lib/folder1:
cd lib/folder1 && $(MAKE)
What if you want to call different targets than all in an unknown number of subdirectories?
The following Makefile uses macros so create a forwarding dummy-target for a number of subdirectories to apply the given target from the command line to each of them:
# all direct directories of this dir. uses "-printf" to get rid of the "./"
DIRS=$(shell find . -maxdepth 1 -mindepth 1 -type d -not -name ".*" -printf '%P\n')
# "all" target is there by default, same logic as via the macro
all: $(DIRS)
$(DIRS):
$(MAKE) -C $#
.PHONY: $(DIRS)
# if explcit targets where given: use them in the macro down below. each target will be delivered to each subdirectory contained in $(DIRS).
EXTRA_TARGETS=$(MAKECMDGOALS)
define RECURSIVE_MAKE_WITH_TARGET
# create new variable, with the name of the target as prefix. it holds all
# subdirectories with the target as suffix
$(1)_DIRS=$$(addprefix $(1)_,$$(DIRS))
# create new target with the variable holding all the subdirectories+suffix as
# prerequisite
$(1): $$($1_DIRS)
# use list to create target to fullfill prerequisite. the rule is to call
# recursive make into the subdir with the target
$$($(1)_DIRS):
$$(MAKE) -C $$(patsubst $(1)_%,%,$$#) $(1)
# and make all targets .PHONY
.PHONY: $$($(1)_DIRS)
endef
# evaluate the macro for all given list of targets
$(foreach t,$(EXTRA_TARGETS),$(eval $(call RECURSIVE_MAKE_WITH_TARGET,$(t))))
Hope this helps. Really helpfull when dealing with paralelism: make -j12 clean all in a tree with makefiles having these targets... As always: playing with make is dangerous, different meta-levels of programming are too close together ,-)

Resources