I have an autotools based C++ project with the following directory structure:
|-- Makefile.am
|-- build
| |-- x86_64-unknown-linux-gnu
| |-- Makefile
| |-- bin
| | `-- utCode
| |-- include
| |-- lib
| | |-- libCode.a
| | `-- libCode.la
| |-- libCode
| | |-- Makefile
| | |-- libCode.la
| `-- utCode
| |-- Makefile
| |-- utCode
|-- include
| `-- code
| |-- File.h
|-- libCode
| |-- File.cpp
|-- Makefile.am
`-- utCode
|-- FileTest.h
|-- FileTest.csv
|-- Makefile.am
|-- UtSetup.sh
`-- code_ut.cpp
I have an unit test project called utCode that requires UtSetup.sh and FileTest.csv during the runtime.
When I run ./utCode from build/x86_64-unknown-linux-gnu/bin/utCode. The tests are failing since UtSetup.sh and FileTest.csv are missing in build/x86_64-unknown-linux-gnu/bin/utCode.
Question:
Is there a way to add a symlink or copy dependency files into build/x86_64-unknown-linux-gnu/bin/utCode using autotools (either in configure.ac or Makefile.am) ?
Related
I have a project structure that looks something like this:
.
└── src
├── Module1
│ ├── source1.cc
│ ├── source2.cc
│ └── source3.cc
├── Module2
│ ├── source1.cc
│ ├── source2.cc
│ └── source3.cc
└── Module3
├── source1.cc
├── source2.cc
└── source3.cc
I have an implicit rule that will create an object file for each source file, and maintain the directory structure (e.g. src/Module1/source2.cc would compile to obj/Module1/source2.o).
However, I would now like to have an implicit rule to create archive files for each module. For example, each object file compiled from src/Module2 would be added to obj/Module2.a. My first idea looked quite similar to my implicit rule for object files:
obj/%.a: $(wildcard obj/%/*.o)
#mkdir -p $(#D);
ar -crs "$#" $^;
This would pass off the work of compiling the object files to the other implicit rule. However, the issue here is that the % character is not expanded.
Is there a way to access the % from the implicit rule within the wildcard function call?
You can do it with Secondary Expansion:
.SECONDEXPANSION:
obj/%.a: $$(wildcard obj/%/*.o)
#mkdir -p $(#D);
ar -crs "$#" $^;
I have a C/C++ project that is organized like this:
project
|
+---- c
| |
| +---- subproject1
| | |
| | +---- bin
| | |
| | +---- obj
| | |
| | +---- src
| |
| +---- subproject2
| |
| +---- bin
| |
| +---- obj
| |
| +---- src
|
+-----+ cpp
| |
| +---- subproject1
| | |
| | +---- bin
| | |
| | +---- obj
| | |
| | +---- src
etcetera
At the project level, there's a Makefile that contains the following:
SUBDIRS = c cpp
all: $(SUBDIRS)
.PHONY: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $#
The c and cpp sub-directories contain similar Makefiles with different SUBDIRS definitions. Typing make at the command prompt from the project, c or cpp directories causes make to change directory to each sudb-directory in SUBDIRS and run make with that sub-directory's Makefile. This behaves exactly as described in the GNU Make Manual and I'm very happy with it. The manual also states that you can add a target like clean after the $# and it will invoke that target in the sub-directory's Makefile. Also great, but what the manual doesn't give guidance on is what to do when SUBDIRS contains more than one sub-directory, as my project and c directories do. I'm going to give you the two methods that I know work and then I'll pose my question.
Add a target for each sub-directory in the clean target's recipe:
clean:
$(MAKE) -C c $#
$(MAKE) -C cpp $#
Loop over each sub-directory in the clean target's recipe (basically the same as method 1, but easier to add more sub-projects to):
clean:
#for subdir in $(SUBDIRS); do $(MAKE) -C $$subdir $#; done
My question is, is there a way of achieving the above that requires using only existing GNU make constructs, something like this (which doesn't work btw):
$(SUBDIRS) clean:
$(MAKE) -C c $#
I would declare per-directory phony clean targets and add them as pre-requisites of clean:
CLEANSUBDIRS = $(addprefix clean-,$(SUBDIRS))
.PHONY: clean $(CLEANSUBDIRS)
clean: $(CLEANSUBDIRS)
$(CLEANSUBDIRS): clean-%:
$(MAKE) -C $* clean
Suppose I have some libraries that I need as prerequisites for a target, and those libraries are stored in directories that contain the library name:
.
|-- Makefile
|-- a
| |-- Makefile
| `-- lib-a
|-- b
| |-- Makefile
| `-- lib-a
`-- out
where out requires both a/lib-a and b/lib-b. Both libs can be built by simply entering the directory and executing make lib-<X> there.
My idea of a Makefile with a pattern rule to avoid repetitions was this, which would have worked if both files were in the same directory or in different directories but with the same name, ie. I had needed to use % only once:
all: out
out: a/lib-a b/lib-b
cat $^ > out
%/lib-%:
make -C $(dir $#)
This doesn't work, however, since the %/lib-% pattern is illegal.
You should never use the raw make command when invoking a sub-make. Always use $(MAKE) (or ${MAKE}) variables.
In short there is no way to write a pattern rule where multiple patterns are required.
If they all have the same recipe then the simplest thing to do is construct the target list and write them all in a single rule:
TARGETS := a b
all: out
OUT_TARGETS := $(foreach T,$(TARGETS),$T/lib-$T)
out: $(OUT_TARGETS)
$(OUT_TARGETS):
$(MAKE) -C $(#D)
.PHONY: all out $(OUT_TARGETS)
I have a directory tree like this:
├── dir_a
│ └── file_1.txt
├── dir_b
│ └── dir_c
│ ├── file_2.txt
| └── file_3.txt
└── file_4.txt
I want to mirror this directory structure to hold the results of a command that processes each text file. I.e., the output would look like this:
├── build
│ ├── dir_a
│ │ └── processed_file_1.txt
│ ├── dir_b
│ │ └── dir_c
│ │ ├── processed_file_2.txt
│ | └── processed_file_3.txt
│ └── processed_file_4.txt
├── dir_a
│ └── file_1.txt
├── dir_b
│ └── dir_c
│ ├── file_2.txt
| └── file_3.txt
└── file_4.txt
I'm not very adept with Makefiles, so my question is: how can I get a Makefile to recreate the directory structure and recursively process all text files to place them into the right place inside the build directory? I'll be running this repeatedly as the input files change, so a Makefile that doesn't process unchanged files seems like the right way to go.
Update:
I should also mention that new input files will be added frequently, so I don't want the Makefile to name them explicitly.
It would be easier if you used stems with different suffixes rather than inserting that "processed_" string, but here's an example that works for me here:
OUTPUTS := build/dir_a/processed_file_1.txt \
build/dir_b/dir_c/processed_file_2.txt \
build/dir_b/dir_c/processed_file_3.txt \
build/processed_file_4.txt
all: $(OUTPUTS)
.SECONDEXPANSION:
$(OUTPUTS): build/% : $$(subst processed_file_,file_,%)
mkdir -p $(dir $#)
cp $< $#
clean:
rm -rf build
You could remove the complication of .SECONDEXPANSION by changing the end of the filename instead of the beginning:
OUTPUTS := build/dir_a/file_1.out \
build/dir_b/dir_c/file_2.out \
build/dir_b/dir_c/file_3.out \
build/file_4.out
all: $(OUTPUTS)
$(OUTPUTS) : build/%.out : %.txt
mkdir -p $(dir $#)
cp $< $#
clean:
rm -rf build
As Carl suggested, you could use secondary expansion, but in conjunction with order-only prerequisites.
BUILD_DIR = build
IN_FILES := dir_a/file_1.out \
dir_b/dir_c/file_2.out \
dir_b/dir_c/file_3.out \
file_4.out
OUT_FILES := $(IN_FILES:%=$(BUILD_DIR)/%)
all: $(OUT_FILES)
.SECONDEXPANSION:
$(OUT_FILES) : $(BUILD_DIR)/%.out : %.txt | $$(#D)/.
# your text processing rule here...
%/. :
mkdir -p $*
| $$(#D) means:
during the secondary expansion calculate the value of $(#D) automatic variable (which is the directory part of the target), and
add the order-only dependency on it, that is ensure that the directory exists, but don't consider remaking the target if it is older than the directory (which is an often case)
I am using the gcc compiler.
My project source tree looks like somewhat like this
test$~: tree .
.
|-- folder
| |-- hello.cpp
| `-- hello.h
`-- main.cpp
1 directory, 3 files
test$~:
The file main.cpp contains the main() function and all the functions invoked by main.cpp
lie in the directory named folder
So far in all my little projects I never had to put some source code under a sub-directory.
What I am looking for, in short, is some gcc command for recursive compilation in sub-directories and their subdirectories and so on... This command should be invoked from the
home directory of the code project.
I couldn't really test it on a c++ library as I don't have one currently, but this should work:
find . -type f -iname *.cpp -execdir g++ {} \;
I just don't remember what happens when the -o option is omitted for gcc. If its necessary then this will at least bring a you a bit closer to a solution. I would recommend using makefiles instead though