makefile, multiple inputs, one output. keeping fresh state. possible? - build

I have one target that takes several input files and generate one.
right now i'm ignoring the freshness state of the input files and running it as a .PHONY
file.out:
$(CMD) input/* file.out
i'd like to have something like:
file.out: $(wildcard input/*)
$(CMD) $^ $#
...So that make would not run CMD every time the input haven't changed.

Remove the .PHONY target.
CMD := cat
file.out: $(wildcard input/*)
$(CMD) $^ > $#

Related

How do I make sure erroneous code does not build in a CI process?

I am writing some C++ library, and I already use some CI (Continuous Integration) process, to make sure the features work.
The build is makefile-based, so the CI script holds a make test line. That target will run the automated tests (say, using Catch), and build passes only if it succeeds.
The good practices mandates that a wrong usage of the library by user code should preferably trigger a compile error, instead of a run-time error. So I included lots of static checking.
However, I want to make sure in my automated testing process that this is really the case (that user code using the library erroneously will fail to build).
So I put up a folder holding several .cpp files, each demonstrating an incorrect usage of the library, thus each of them should fail to build.
My problem is that if I add a new target in my makefile to build these, it will return after first failure.
What I want to do is make sure that all these files fail to build, and return 0 only in that case.
How can I write a target that performs this ?
Some (not working) code, that will return after first failure.
SRC_FILES := $(wildcard *.cpp)
OBJ_FILES := $(patsubst %.cpp, %.o, $(SRC_FILES))
all: $(OBJ_FILES)
#echo "done"
%.o: %.cpp
$(CXX) -o $# -c $<
If I basically ignore the failures (prepending line with -), I won't be able to check that all of the files are incorrect.
The only way to do it if you want to use the same pattern rule, is through recursive make and passing the -k flag (--keep-going), like this:
TEST_SRCS := bad1.cpp bad2.cpp bad3.cpp
.PHONY: test_compile
test_compile:
$(MAKE) -k $(TEST_SRCS:%.cpp=%.o)
Another option is to compile them all in a loop in a single recipe:
test_compile:
ok=true; \
for src in $(TEST_SRCS); do \
$(CXX) -o $${src%.cpp}.o -c $$src || ok=false; \
done; \
$$ok
srcs := fail1.cpp fail2.cpp fail3.cpp
failed := ${srcs:.cpp=.failed}
PHONY: test
test: ${failed} ; : $# Success
${failed}: %.failed: %.cpp
! gcc blah blah $< -o ${#:.failed=.o}
touch $#
What happens here is that when you want to build test, make first tries to build fail1.failed.
If the compile succeeds, make fails with an error.
OTOH if the compile fails, the output file fail1.failed is created.
BTW, make knows that fail1.failed depends on fail1.cpp.
If the .failed is newer than the .cpp, the test will not even run.
Nice.
Same for fail2.failed and fail3.failed. Parallel safe, and if you get your dependencies right, only the tests that need to run get run. The whole point of make really.
Accepting answer form #MadScientist but for the record, seems this can be done also this way:
SRC_FILES := $(wildcard *.cpp)
OBJ_FILES := $(patsubst %.cpp, %.o, $(SRC_FILES))
all: $(OBJ_FILES)
#echo "done"
%.o: %.cpp
! $(CXX) -o $# -c $<
Just by reversing the return value from the compile shell command: if a single file succeeds, then make will immediately exit with an "error" return value.

Makefile in sub-directory

I am trying to write a makefile in a subdirectory of my eclipse makefile project.
MyProject \
test.cpp
Build\
Makefile
I am also trying to create a generic makefile. I am having trouble defining the targets since the build is not happening in the same directory as the source.
CC = g++
CC_FLAGS = -g3
EXEC = test
SOURCEDIR = ..
SOURCES = $(shell find $(SOURCEDIR) -name '*.c' -o -name '*.cpp')
OBJECTS = $(addsuffix .o,$(subst ../,,$(SOURCES)))
.DEFAULT_GOAL = all
$(EXEC): $(OBJECTS)
$(CC) $(OBJECTS) -o $(EXEC)
%.o: %.cpp
$(CC) -c $(CC_FLAGS) $< -o $#
.PHONY: clean
clean:
rm -f $(EXEC) $(OBJECTS)
.PHONY: all
all: $(EXEC)
Right now when I build I get the error...
make all
make: *** No rule to make target 'test.cpp.o', needed by 'test'. Stop.
Can anyone tell me why this is not working or recommend a better approach.
If you change your dependency from object to source as follows:
%.cpp.o: $(SOURCEDIR)/%.cpp
it seems to work.
In general I would prefer to NOT do anything in a build dir, because I personally expect a build dir is a temporary dir which can be removed completely for distribution which is not the case if the Makefile resists there. But this is a matter of taste.
Also I do not prefer to use all c/cpp you find as objects/sources in the make process. If you need to add files for different variants in your projects, you enter a nightmare to change all these things later.
And also as a hint: Typically objects are <basename>.o and not <basename>.cpp.o
And another one:
Users expect that the clean target also remove the executable. If not, you will never see a rebuild by simply do make clean; make, because the executable is in place and all dependencies are fulfilled.

Save object files in same makefile directory using depend

I have this makefile
appname := fun
srcfiles := $(shell find .. -name "*.cpp")
headerfiles := $(shell find .. -name "*.hpp")
objects := $(patsubst %.cpp, %.o, $(srcfiles))
all: $(srcfiles) $(appname)
$(appname): $(objects)
$(CXX) $(LDFLAGS) -o $(appname) $(objects) $(LDLIBS)
depend: .depend
.depend: $(srcfiles) $(headerfiles)
rm -f ./.depend
$(CXX) $(CXXFLAGS) -MM $^>>./.depend;
clean:
rm -f $(appname) $(objects)
dist-clean: clean
rm -f *~ .depend
include .depend
Where the makefile's parent directory contain all the code (.hpp and .cpp files). Unfortunately, the .o files are saved in the source code, while I want that they're saved in the same directory of the executable (and makefile). This is the same of Default in Eclipse CDT.
How can I modify makefile in order to do that?
PS: I found similar questions, like this one, but none of them used depend for defining the $(objects) task (they're all in `%.o% form).
When you set your objects variable you are simply taking the full pathname to the .cpp file and replacing the suffix with .o. So if you have a file like my/sub/dir/foo.cpp then objects will contain the path my/sub/dir/foo.o. So, of course when you write a rule $(appname): $(objects), make is going to try to build the file my/sub/dir/foo.o. If you want it to build just foo.o instead, then you have to strip off the path as well, not just replace the suffix:
objects := $(patsubst %.cpp,%.o,$(notdir $(srcfiles)))
Now, of course, make will say it doesn't know how to build foo.o, because the default rules only know how to build a .o from a .cpp, not from a .cpp file stashed in my/sub/dir.
To make this work the simplest solution is to use VPATH and you can construct the value for VPATH from the list of directories you got from srcfiles, like so:
VPATH := $(sort $(dir $(srcfiles)))
You might also consider using a better dependency generation solution, for example the one described here.

Using makefile arguments without foo=

I have a makefile I use to compile a single file. When I need to pass an argument, I use target=targetFile.
The script takes the argument, looks for the file (within the same directory) that has the same value as the argument and compiles it.
I use this for compiling problems from uhunt and uva, which use a single c++ file. So I dont' need multiple makefiles for multiple source files. Single makefile for multiple source files is the reason I made the makefile.
Here's the code I have so far
OBJS = $(target).o
CC = g++
CFLAGS = -Wall -g -std=c++11
INCLUDE = -I./$(target)
#default command to run
all : Main-$(target) clean run
#compile and build
Main-$(target) : $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
%.o : %.cpp
$(CC) -c $(CFLAGS) $<
#remove object and any other garbage files.
clean:
rm -rf -d $(target).o *~ *% *# .#*
#remove the compiled file
clean-all:
$(clean) rm Main-$(target)
#run the compiled file
run:
./Main-$(target)
The command I use to compile is,
make target=sourceFile
Also I don't include the file extension, I have all my source file extensions to be cpp
What I want in the end is:
make sourceFile
Just a side note, for using the command clean and clean-all, I use
make target=sourceFile clean
make target=sourceFile clean-all
I'd prefer if I can use:
make sourceFile clean
make sourceFile clean-all
You may use common Makefile variable MAKECMDGOALS that contains all targets passed to make.
Please try this variant
CC = g++
CFLAGS = -Wall -g
MAKECMDGOALS := $(filter-out clean, $(MAKECMDGOALS))
.PHONY: $(MAKECMDGOALS)
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
clean:
rm -f *.o
Here the lines
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
will generate separate build targets for each word in MAKECMDGOALS.
Note, we need this Makefile to know that 'clean' is a target for removing stuff, but not to attempt build Main-clean. This why we remove clean from MAKECMDGOALS using filter-out function.
So if we run make a b clean, the build system will generate automatically targets for building Main-a and Main-b and then use already written clean target
Disclaimer -- this is a non-standard use of Make, and will therefore open up all kinds of corner cases, so I don't recommend it. This is better suited for a shell script calling make. That being said... it is an interesting question.
You can't do make xxx clean, and not have it try to build xxx (unless you do some really nasty cludge using recursive make, but I won't go there). You could do something like make clean-xxx though, as follows:
%:Main-%
Main-%:%.cpp
$(CC) $(CFLAGS) $< -o Main-$#
clean-%:
rm Main-$*
Notice that %-clean has a shorter stem, and therefor takes precedence over the % if the make target starts with clean-.

makefile: Why does this simple makefile only process the first source file?

[SOLVED]
I'm having trouble getting this simple makefile to work properly.
This should build the three source files NeonAs1.cpp NeonAs2.cpp NeonAs3.cpp to object files in the 'obj' folder.
This works but it only ever attempts to build NeonAs1.cpp and then completes without error.
Any ideas?
WORKSPACE=../../workspace/
SRC_FOLDER=$(WORKSPACE)/ProjectNeon/
LOCAL_SRC_FILES=NeonAs1.cpp NeonAs2.cpp NeonAs3.cpp
vpath %.cpp $(SRC_FOLDER)
OBJECTS = $(patsubst %.cpp,obj/%.o,$(LOCAL_SRC_FILES))
$(OBJECTS): | obj
obj:
#mkdir -p $#
obj/%.o : %.cpp
#echo $<
#$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
-rm -f $(LIBRARY) obj/*.o
Update 1: if I add a explicit all target like:
all: $(OBJECTS)
Then if I do an explicit:
make all
It works fine.. How can I make it work when I just do a make with no 'all' target
Update 2: Solved, I just needed to move my all target above the $(OBJECTS) target.
The default behavior of make is to only build the first target listed in your Makefile. I don't see any target listed earlier than $(OBJECTS): | obj. Therefore, the "first target rule" will build the first thing listed in $(OBJECTS).
To get all of your $(OBJECTS) built, you need a target for your final executable that depends on $(OBJECTS).
To make your Makefile meet common convention, you'll want to list a target named all early in your Makefile that depends on your executable as well. That way, when you type make or make all, it will build your $(OBJECTS) and your executable.
For debugging purposes, you might add a target named debugvars: that just executes #echo OBJECTS=$(OBJECTS) to make sure $(OBJECTS) is set as you expect. To run that target, you can then type make debugvars. That's a handy trick I've used many times to debug variables in a Makefile.