Here is the part of my makefile to compile a project in OCaml and generate a binary:
all: $(CMX_DOMAIN) analyze
export OCAMLRUNPARAM=b
I would like make tests to do the follows:
Compile the project
run ./$(BIN) to each files in the folder tests/
Could anyone tell me how to write this part of tests in makefile?
Something like:
tests: all
for f in tests/*; do ./$(BIN) $$f || exit 1; done
? Or do you need more than that?
Related
I have the following Makefile entry:
TEST_DIRS = abcd pqr xyz
test_lib :
for dir in $(TEST_DIRS); do \
$(MAKE) -C $$dir; \
done
run :
./abcd/test/abcd_test.o --log_level=message
./pqr/test/pqr_test.o --log_level=message
./xyz/test/xyz_parser_test.o --log_level=message
test : test_lib run
I don't want to write 3 separate commands for run target instead make it generic. So that everytime a new test file gets added, I dont want add a new command under run target. Can somebody help me?
TESTS := $(addprefix TEST_, $(TEST_DIRS))
run: $(TESTS)
TEST_%:
./$*/test/$*_test.o --log_level=message
Assuming the naming scheme is consistent (and those are just oddly named binaries and not actually object files) then something like this should work:
Using a shell loop:
run :
for name in $(TEST_DIRS); do \
./$$name/test/$${name}_test.o --log_level=message; \
done
Using make foreach:
run :
$(foreach name,$(TEST_DIRS),./$(name)/test/$(name)_test.o --log_level=message;)
I have a following directory structure
src/
kernel/
gui/
In kernel/ directory, I have generated a library named libkernel.a and in gui/ directory I have to use libkernel.a to generate libgui.a.
I added this to the gui/Makefile.am
libgui_a_LIBADD = $(srcdir)/kernel/libkernel.a
But I am getting the following error
*** No rule to make target `kernel/libkernel.a', needed by `libgui.a'. Stop.
So I don't understand how do I link libkernel.a properly.
Edit/Explanation
In gui/ directory I have one somegui.cpp file that uses xclass.h which is in kernel/ directory.
So in order to solve that issue I am asking how should I proceed.
Try to use non-recursive automake to avoid these kind of problems.
https://www.flameeyes.eu/autotools-mythbuster/automake/nonrecursive.html
Sidenode: use $(top_builddir) when referring to compiled objects. Otherwise your code will break when srcdir != builddir
If you really have to do it recursive, than you can add a rule to gui/Makefile.am
$(top_builddir)/kernel/libkernel.a:
cd $(top_builddir)/kernel && $(MAKE)
Note: If you want to use parallel make (-j) you also need to make sure that in src/Makefile.am there is a dependency between the subdirs
.PHONY kernel gui
kernel:
cd kernel && $(MAKE)
gui: kernel
cd gui && $(MAKE)
When I tried my makefile, I got error saying that No such file or directory, but my directory is right there, what do I do wrong? Thanks.
my project structure :
dev |--- ev
|--- display
|--- install ( makefile is here, try to call makefiles in ev and display folder)
My makefile :
MODULES :=ev display
SRC_DIR :=$(addprefix ../, $(MODULES))
BUILD_DIR:=$(addsuffix /build, $(SRC_DIR))
x:=../ev ------> add temporarily just for test,
------> the same error if x:=$(HOME)/dev/ev
INSTALL_DIR:=EX Frameworks Add-ons
INSTALL_DIR:=$(addprefix $(HOME)/EX/, $(INSTALL_DIR))
vpath %.cpp %.java $(SRC_DIR)
.PHONY: all clean
checkdirs: $(INSTALL_DIR)
$(INSTALL_DIR):
#echo "INSTALL DIR"
#mkdir -p $#
define make-goal
$1:
#echo "start building each part"
cd $# && make -f Makefile_new.osx clean
cd $# && make -f Makefile_new.osx package
endef
clean:
#echo "clean up"
#echo "BUILD_DIR IS $(BUILD_DIR)"
#rm -rf $(BUILD_DIR)
all:
#echo "start build subdirectory"
#echo "SRC_DIR IS $(SRC_DIR)"
#echo "x is $(x)"
$(call make-goal, $(x))) ----> when it comes to here, I got error message
The error messages:
x is ../ev
../x:
make: ../ev:: No such file or directory.
I guess it is about relative path, because I call this makefile from Install folder, then $(x) can't be found from Install folder, but when I tried to make a folder named ev (Install/ev), I still got the same error.
I think it must be something basic I missed here, but what it is.
Thanks.
Update:
I am trying to build a project which includes several sub-projects. the structure is:
dev |---- ev
|---- edf
|----- dt
|------af
|------Install
Inside of Install, I have a makefile, which is at the top level. The makefile in Install folder will call makefiles in other folders to build different subjects,
Ideally, I want to build every sub projects without touching sources. My sources include c++ and java code.
It's not clear what you're trying to do. Also due to some indentation hiccups I can't be sure, but you appear to be defining a variable make-goal that contains a template for a make rule, then using it with $(call ...) inside the recipe for the all target. That cannot work: you cannot create a make rule inside the recipe for another make rule!
The reason this fails is that the $(call ...) is expanding to content which is added to the recipe of the all target, so instead of creating a new make rule it's treating the result as a shell script. The first line is $1:, and you passed in ../ev, so make is trying to run the command ../ev: just as the error shows you.
If you describe what you want to do at a higher level we can give you some ideas on how to do it.
ETA:
If you just want your all target to also build a subdirectory, there's no need for all this complex GNU make advanced capabilities. That stuff is only needed when you get to guru-level makefile creation. Simple "build a target after another target is finished" is the exact thing make was designed to do: nothing special is needed to do that.
For example:
.PHONY: all $(SRC_DIR)
all: $(SRC_DIR)
$(SRC_DIR):
#echo "start building $#"
cd $# && $(MAKE) -f Makefile_new.osx clean
cd $# && $(MAKE) -f Makefile_new.osx package
This is still a pretty non-standard setup but I think it will work the way you want. Remember you'll have to either move the all target up to be the first one in the makefile, or you'll have to run make all explicitly: make only builds the first target in the makefile unless you give it specific targets on the command line.
I want to create a Makefile (in a parent dir) to call several other Makefiles (in sub dirs) such that I can build several binaries (one per project sub dir) by invoking just the one parent Makefile.
My research has been hampered by finding loads of stuff on recursive Makefiles, but I think this is where you are trying to build several directories Makefiles into a single binary?
Maybe what I want to do is better handled by a shell script perhaps invoking make in each sub directory in turn, but I thought a Makefile might be a more elegant solution?
any pointers gratefully received
PS using linux and the GNU tool chain
The for loop solution given in the first answer above actually shouldn't be used, as-is. In that method, if one of your sub-makes fails the build will not fail (as it should) but continue on with the other directories. Not only that, but the final result of the build will be whatever the exit code of the last subdirectory make was, so if that succeeded the build succeeds even if some other subdirectory failed. Not good!!
You could fix it by doing something like this:
all:
#for dir in $(SUBDIRS); \
do \
$(MAKE) -C $${dir} $# || exit $$?; \
done
However now you have the opposite problem: if you run "make -k" (continue even if there are errors) then this won't be obeyed in this situation. It'll still exit on failure.
An additional issue with both of the above methods is that they serialize the building of all subdirectories, so if you enable parallel builds (with make's -j option) that will only happen within a single subdirectory, instead of across all subdirectories.
Eregrith and sinsedrix have solutions that are closer to what you want, although FYI you should never, ever use "make" when you are invoking a recursive make invocation. As in johfel's example you should ALWAYS use $(MAKE).
Something like this is what you want:
SUBDIRS = subdir1 subdir1 subdir3 ...
all: $(addprefix all.,$(SUBDIRS))
all.%:
# $(MAKE) -C '$*' '$(basename $#)'
.PHONY: $(addprefix all.,$(SUBDIRS))
And of course you can add more stanzas like this for other targets such as "install" or whatever. There are even more fancy ways to handle building subdirectories with any generic target, but this requires a bit more detail.
If you want to support parallel builds you may need to declare dependencies at this level to avoid parallel builds of directories which depend on each other. For example in the above if you cannot build subdir3 until after both subdir1 and subdir2 are finished (but it's OK for subdir1 and subdir2 to build in parallel) then you can add something like this to your makefile:
all.subdir3 : all.subdir1 all.subdir2
You can call targets in subdirectory makefiles via
all:
$(MAKE) -C subdirectory1 $#
$(MAKE) -C subdirectory2 $#
...
or better
SUBDIRS=subd1 subd2 subd3
all:
#for dir in $(SUBDIRS); \
do \
$(MAKE) -C $${dir} $#; \
done
you should indeed use cmake to generate the Makefile automatically from a given CMakeLists.txt configuration file.
Here's a random link to get you started. Here you can find a simple sample project, including multiple subdirectories, executables, and a shared library.
Each makefile can have several target, it's still true with recursive makefiles, usually it's written:
all: target1 target2 target3
target1 :
make -C subdir
Then make all
Imagine the following folder structure:
project
src
code.c
makefile
bin
How can I compile code.c to code.o and directly put it inside bin? I know I could compile it to code.o under src and the do "mv code.o ../bin" but that would yield an error if there were compile errors, right? Even if it works that way, is there a better way to do it?
Thanks.
The process should or should not "yield an error" depending on what you mean. If there are compiler errors, you'll know it.
That said, there are several ways to do it with make. The best in this case are probably:
You could put the Makefile in bin. Make is good at using files there to make files here, but not the other way around.
You could specify the target path in the makefile target:
$(MAIN_DIR)/bin/%.o: %.c
$(COMPILE)...
A little late, but if it can be helpful.
This is how I get the up one level directory path from where the makefile is.
$(subst $(notdir $(CURDIR)),,$(CURDIR))
if your project looks like that:
~/myProject/
src/
Makefile
#all the .c and .cpp
bin/
#where you want to put the binaries.
$(CURDIR) will output ~/myProject/src
$(subst $(notdir $(CURDIR)),,$(CURDIR)) will output ~/myProject
You could try moving, but only when the compilation was successful using &&:
code.o: code.c code.h
g++ -c code.c && mv code.o ../
mv code.o ../ will only be executed if g++ returned 0, which is when the compilation was successful. This may not be suitable solution for you if you have very complicated makefile, but I thought I'd share what I know.
You can still use the move approach and survive compiler errors:
cc -c code.c && mv code.o ../bin
This won't run the "mv" part if the "cc" part fails.