Exlude Directory from Source Files in Makefile? - makefile

NOTE: I use Mingw Make.
Basically, I've got a makefile with the following snippet for source files:
SRC_FILES = $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*/*.c $(SRC_DIR)/*/*/*.c)
SRC_FILES := $(filter-out $(SRC_DIR)/sys/mswin/win_main.c, $(SRC_FILES))
Not the prettiest, I'll admit I'm still a beginner, but it does work. However, the second line shows what I'd like to exclude. Issue is, I currently have to do this per file I want to exclude. (Note: I've tried replacing win_main.c with *.c, doesn't work).
What I'd like to be able to do is exclude the entire 'sys' directory from SRC_FILES, but I'm honestly unsure of how to do this. I attempted to have:
SRC_FILES := $(filter-out $(SRC_DIR)/sys, $(SRC_FILES))
But this didn't work, either. I'm honestly unsure if this is even possible at this point, but I hope I'm just missing something. Any help is appreciated!
EDIT: I know that the project structure itself isn't ideal, but that's not really the point of this, however improvement tips are certainly apprectiated, and if you need any other information to answer the question just ask.

Easy enough; filter-out takes a %-pattern as an argument:
SRC_FILES := $(filter-out $(SRC_DIR)/sys/%,$(SRC_FILES))

Related

Makefile example issue regarding dir variable

Hello I am a bit new to makefiles, i know the basics and thought I'd work through an example i found online. However i ran into something that doesn't seem right and i was hopping somone could help clear things up. The example can be found at the following link:
https://riptutorial.com/makefile/example/21376/building-from-different-source-folders-to-different-target-folders
My specific question is regarding the following line:
SOURCEDIRS = $(foreach dir, $(DIRS), $(addprefix $(SOURCEDIR)/, $(dir)))
I was wondering how the makefile could evaluate $(dir) when the dir variable was not assigned anywhere? is dir some sort of pre defined GNU Makefile variable or am i missing something?
Any help is appreciated, thanks
First, look up foreach. The function iterates through $(DIRS), assigning each word of it to dir in turn, and evaluating $(addprefix $(SOURCEDIR)/, $(dir)). This has the effect of prepending $(SOURCEDIR)/ to each word in $(DIRS).
Then look up addprefix. This function can do all of the work by itself, so foreach is completely unnecessary in this example. This will suffice:
SOURCEDIRS = $(addprefix $(SOURCEDIR)/,$(DIRS))

How to use GNU make to update files in all subdirectories containing a particular file?

In my project, I have a set of sub-directories that contain package.yaml files, for e.g.:
A/package.yaml
B/package.yaml
C/package.yaml
If I run hpack A/package.yaml, the file A/A.cabal is (re-)generated. The list of such directories can change over time, so I want to use GNU make to find all immediate sub-directories containing package.yaml files and generate the corresponding .cabal files using hpack.
I tried this based on another question, but it didn't work:
HPACK_FILES := $(wildcard */package.yaml)
PKG_DIRS := $(subst /,,$(dir $(HPACK_FILES)))
CABAL_FILES := $(addsuffix .cabal,$(join $(dir $(HPACK_FILES)),$(PKG_DIRS)))
test:
#echo $(CABAL_FILES)
update-cabal: $(CABAL_FILES)
%.cabal: package.yaml
hpack $<
However, make update-cabal says there's nothing to be done. make test however does output the right cabal files. How can I fix this?
Cheers!
The problem is this:
%.cabal: package.yaml
There is no file package.yaml. The files are named things like A/package.yaml. That is not the same thing.
Because the prerequisite doesn't exist, make decides that this pattern rule cannot match and so it goes looking for another rule that might be able to build the target. It doesn't find any rule that can build the target, so make says there's nothing to do because all the output files already exist.
Unfortunately what you want to do is not at all easy with make, because make is most comfortable with input and output files that are tied together by the filename with extensions, or similar. And in particular, it has a really hard time with relationships where the variable part is repeated more than once (as in, A/A.cabal where the A is repeated). There's no easy way to do that in make.
You'll have to use an advanced feature such as eval to do this. Something like:
# How to build a cabal file
%.cabal:
hpack $<
# Declare the prerequisites
$(foreach D,$(dir $(HPACK_FILES)),$(eval $D/$D.cabal: $D/package.yml))

Generic rule adding path to target

I want to build a Makefile that looks like below:
binfolder := bin
objs := #...
bins := program1 secondprogram thethirdprogram
all: $(bins)
#does not work, how can I express this?
$(bins):%: $(binfolder)/%
$(binfolder)/%: $(objs) _mainobj_%.o
#g++ ...
Note the line that is not correct, but hopefully convey what I want accomplished. I want to be able to make targets without writing out the path myself, and without having to write an extra line per program. I guess the part of the problem is that i can not just use % alone as a target. How can I solve this?
It looks like your problem is with trailing whitespace:
binfolder := bin #<- notice trailing whitespace.
# bindfolder is actually "bin "...
So now your rule
$(bins):%: $(binfolder)/%
expands to:
program1 secondprogram thethirdprogram:%: bin /%
which is likely causing your problem. To check for things like this, you can add the following:
$(info binfolder is "$(binfolder)")

Filtering using multiple wildcards

I've git a project where, at some point in its Makefile, I'm filtering out stuff from a certain directory:
relevant = $(filter-out irrelevant/%,$^)
Now I want to use this in a VPATH-enabled environment. So the paths of my dependencies in $^ might not start with irrelevant any more, but instead something like ../src/irrelevant or similar.
Is there a way to filter-out anything that contains irrelevant, in any position? I.e. something like the following?
relevant = $(filter-out %irrelevant/%,$^)
This doesn't work, since apparently patterns for filter-out can contain only a single % wildcard. I know I could possibly achieve this via a shell invocation, grep or whatever, but I was hoping for some combinations of functions inside the Makefile.
Try
relevant = $(foreach a,$^,$(if $(findstring irrelevant,$a),,$a))

Variable arguments list to a Makefile

I would like do something like following. I would like to have a variable argument list for a Makefile.
make VAR_ARG_LIST=src1,src2,src3,src4
Can I do like this? If I can, how do I extract src1,src2 or src3 from the variable VAR_ARG_LIST inside the Makefile?
Thanks,
If you want a list of targets in a macro for make to use, use blanks to separate them (and quotes to enclose them) on the command line:
make VAR_ARG_LIST="src1 src2 src3 src4"
This can be used inside the makefile without much trouble at all:
PROGRAMS = ${VAR_ARG_LIST}
all: ${PROGRAMS}
and it will go off and create the programs src1, ... src4 from the rest of the rules in the makefile.
If that isn't roughly what you're after, then you need to clarify your question.
You really haven't provided enough information for a solution. Why do you want to extract those values? What do you want to do with them?
However, I can answer the question you asked and hope it is useful. If you're using GNU make you can do this:
COMMA := ,
VAR_ARG_LIST_A := $(subst $(COMMA), ,$(VAR_ARG_LIST))
VAR_ARG_LIST_1 := $(word 1,$(VAR_ARG_LIST_A))
VAR_ARG_LIST_2 := $(word 2,$(VAR_ARG_LIST_A))
etc.

Resources