GNU make not recognizing % - makefile

I'm trying to make a makefile for compiling various examples that are within a subfolder. The makefile consisting of just:
S_1_2.exe : Twister.cpp Parsing.cpp ./Surfaces/S_1_2.cpp
g++ -o $#.exe $^ -I . -W -Wall
Works fine when run with the command "make S_1_2.exe". However:
%S_1_2.exe : Twister.cpp Parsing.cpp ./Surfaces/S_1_2.cpp
g++ -o $#.exe $^ -I . -W -Wall
fails, even when run with the command make S_1_2.exe, with the error "make: * No rule to make target 'S_1_2.exe'. Stop."
Shouldn't %S_1_2.exe do pattern matching and so match S_1_2.exe? In which case why is it not matching this rule?
I am using GNU Make 3.81

The percentage symbol matches a non-empty string. So you should use %_1_2.exe or better yet - %.exe. I don't know if there is any other symbol that matches empty strings too.

The % is for matching a part of the target against the same part in one or more dependencies.
You can't omit it from all dependencies.

Related

GNU make generate assembly first, them compile them to .o and link

SOURCE=a.c b.c c.c
ASM=$(patsubst %.c,%.s, $(SOURCE))
all:%.o
gcc -o test $^
$(ASM):%.c
gcc -S -o $# $<
%.o:%.s
gcc -c -o$# $<
I want to generate assembly code (.s) first, then compile the assembly code to object (.o), then link them.
But it seems above makefile code does not work. What is the correct code?
When asking questions, does not work is never very useful... if it worked you probably wouldn't be asking a question! :-) Instead you should always show the command you ran and the output you received (or at least the failing part of the output if it's long). Please cut and paste the actual text rather than paraphrasing messages. Also, including the version of the make program you're using (make --version) and the platform you're running on is often helpful.
Luckily this time we can figure out the problem without this information:
This:
$(ASM):%.c
gcc -S -o $# $<
where ASM is a.s b.s c.s, is not a pattern rule because the targets don't contain a pattern character %. That means the prerequisite %.c is not treated as a pattern, but as an actual file name, literally %.c which obviously doesn't exist.
Similarly, this:
all: %.o
has the same problem: all is a target, so this depends on the literal file named %.o which doesn't exist, and can't be created.
Also as a general rule every recipe that creates a target must create the actual target you told make it would, so this all rule is wrong because the target name is all but the recipe creates the target test.
Finally, it's a very bad idea to name your program test because test is a common UNIX program and a shell built-in, so if you run test it won't do the right thing (if you run ./test it will work).
You want to have all depend on the program you want to build, say mytest, and mytest should depend on the actual .o files:
all: mytest
mytest: $(SOURCE:.c=.o)
gcc -o $# $^
Next, you need to define a pattern rule that knows how to create an assembly file from a source file:
%.s : %.c
gcc -S -o $# $<
That, along with your other pattern rules, is all you need: make will figure it all out from that.
Finally, make has a built-in rule that tells it how to build object files directly from source files. It's best to get rid of this to force make to use your rules; add this to your makefile to delete it:
%.o : %.c

No rule to make target 'openmp'?

The following is defined in the makefile:
CXX = g++
CXXFLAGS = -std=c++11
I would like to compile my code with OpenMP directives without changing the original makefile (which runs perfectly). The manual suggests a way to do this, is by changing it on the command line. However, when I run,
make CXXFLAGS=-std=c++11 -fopenmp
the error mentioned before pops up. Can someone help me understand what I'm doing wrong?
The problem here is the space between -std=c++11 and -fopenmp. It splits these two arguments up and the -fopenmp is interpreted as the option -f then openmp is interpreted as a makefile that make attempts to build because it can't find it in the current directory.
You need to execute make with quotes (") like
$ make CXXFLAGS="-std=c++11 -fopenmp"
this will pass CXXFLAGS= -std=c++11 -fopenmp to make. We can see this behaviour with the following simple makefile.
CXX = g++
CXXFLAGS = -std=c++11
all:
#echo $(CXXFLAGS)
Running make will produce the output
$ make
-std=c++11
Running make CXXFLAGS="-std=c++11 -fopenmp" will produce
$ make
-std=c++11 -fopenmp
the correct output and what we were hoping to achieve.
As an aside the command, make CXXFLAGS= -std=c++11 -fopenmp, in your question should produce more errors than just
make: openmp: No such file or directory
make: *** No rule to make target 'openmp'. Stop.
because of the space between CXXFLAGS= and -std=c++11. I get
$ make CXXFLAGS= -std=c++11 -fopenmp
make: invalid option -- =
make: invalid option -- c
make: invalid option -- +
make: invalid option -- +
make: invalid option -- 1
make: invalid option -- 1
If for instance you want to compile with -std=c++14 instead of -std=c++11 you would need to execute make with
$ make CXXFLAGS=-std=c++14
note: no space, or equivalently with
$ make CXXFLAGS="-std=c++14"
again without a space.
Space - The Final Frontier. You need quotes as in
make CXXFLAGS="-std=c++11 -fopenmp"
The shell splits command line words at word boundaries delimited by white space. Quoting is used to avoid word-splitting.

GNU make is adding white space after -I (shared directory) option

I'm trying to use armclang compiler through a GNU makefile, but there is a clash between both tools when using -I option.
For armclang compiler, the -I means "Adds the specified directory to the list of places that are searched to find included files.Syntax -Idir" without a space.
For GNU makefile ‘-I dir’ has the same meaning (but with a space).
in My makefile I have the following:
$(aarch32_bootobj): %.o: %.s
#echo " [ASM ] $<"
#armclang --target=armv8a-arm-none-eabi -Icommon/shared -c $< -o $#
When Running the Makefile, I'm getting the following Warning and Error :
armclang: warning: argument unused during compilation: '-I common/shared'
aarch32/shared/bootcode.s:32:10: error: Could not find include file 'boot_defs.hs'
Where boot_defs.hs exists under common/shared
When running the same armclang command outside the makefile, it works. therefore I'm assuming that makefile has formatted the -Icommon/share option and added automatic space just after the -I.
Is there any way to run the armclang command correctly? in other worlds, is it possible to let the makefile parse the -Icommon/shared without any automatic formatting?
I have been trying a lot of tricks to workaround that without any success.
Thanks a lot In advance.
GNU make doesn't split the -Icommon/shared option, and even if it did armclang would be able to parse that. If you remove the # from the armclang call in the Makefile, you'll see exactly what make does and that the -Icommon/shared parameter remains intact.
Your problem is with armclang; see this bug on the tracker. It doesn't pass -I flags to its integrated assembler. A workaround, then, should be to pass -no-integrated-as to armclang:
#armclang -no-integrated-as --target=armv8a-arm-none-eabi -Icommon/shared -c $< -o $#
If that doesn't work, replace the .include directive with #include and either rename your asm files to .S (upper-case S), which indicates that they need C preprocessing, or pass armclang the -x assembler-with-cpp flag. The behavior of this is documented here.

% not matching zero or more characters in rule?

According to the manual on Defining and Redefining Pattern Rules (and if I am reading it correctly):
‘%’ character matching any sequence of zero or more characters...
But the following is not matching both bench.cpp and bench2.cpp:
bench%.o : bench%.cpp
$(CXX) $(CXXFLAGS) -DCRYPTOPP_DATA_DIR='"$(PREFIX)/share/cryptopp"' -c $<
%.o : %.cpp
$(CXX) $(CXXFLAGS) -c $<
Here's what I see when running make:
$ rm bench*.o
$ make static dynamic cryptest.exe PREFIX=/usr/local
make: Nothing to be done for `static'.
make: Nothing to be done for `dynamic'.
g++ -DNDEBUG -g -O2 -fPIC -march=native -pipe -c bench.cpp
g++ -DNDEBUG -g -O2 -fPIC -march=native -pipe -DCRYPTOPP_DATA_DIR='"/usr/local/share/cryptopp"' -c bench2.cpp
Above, both bench.cpp and bench2.cpp should have -DCRYPTOPP_DATA_DIR='"/usr/local/share/cryptopp"'. I also tried using the asterisk (*) with no joy.
How do I craft a rule that matches both bench.cpp and bench2.cpp?
According to the link you provided
A pattern rule contains the character ‘%’ (exactly one of them) in the
target; otherwise, it looks exactly like an ordinary rule. The target
is a pattern for matching file names; the ‘%’ matches any nonempty
substring, while other characters match only themselves.
So % doesn't match empty strings.
‘%’ character matching any sequence of zero or more characters...
refers to the definition of vpath which is totally different.
I'm afraid you'll have to use bench1 instead of bench. Alternatively you can use macro to defines 2 rules but write it only once.
Well, I happened to stumble across the proper section of the documentation on this.
According to 4.4 Using Wildcard Characters in File Names, I should probably use an asterisk in this case.
And according to Stallman and the GNUMake manual, % is not a wildcard for specifying file names:
A single file name can specify many files using wildcard characters.
The wildcard characters in make are ‘*’, ‘?’ and ‘[…]’ ...

Make Pattern Rule not recognized

I'm currently writing a makefile that is able to compile different targets (Like Debug, Development, Release). The linking and compiling rules look like that:
$(DEVELOPMENT_OUT): $(subst rep,development,$(OBJS))
g++ -o $(DEVELOPMENT_OUT) $(subst rep,development,$(OBJS))
obj/development/%.o: src/%.cpp
g++ -c -MMD -MP -MF"$(#:%.o=%.d)" -MT"$(#:%.o=%.d)" -o "$#" "$<"
Now, I get this output:
make: *** No rule to make target 'obj/development/Main.o', needed by 'bin/Development.exe'. Stop.
But shouldn't the pattern rule apply for the Main.o?
I use GNU Make 3.82.90 of MinGW.
There's not enough information here to say why it doesn't work. If you're sure you have a file src/Main.cpp then make should choose that rule. Is the cpp file a source file, or a generated file? If it's generated then maybe the real problem is lower down, where the generating happens. You can try using make -d to see what make is doing and why it doesn't like this rule.

Resources