In makefile, how to use static pattern rules with file name containing dollar sign? - shell

I have .c files need to be compiled, for example:
$main.c
$print.c
...
They were generated by another program. I would like to write a makefile that will compile them separately so that I can do it with -j 8.
My plan was to use static pattern rules like the following:
SRCS = $(wildcard ./*.c)
OBJS = $(patsubst %.c,%.o,$(U_SRC))
$(OBJS):%.o:%.c
gcc $(CFLAGS) -c $< -o $#
However, due to the dollar sign, the file names cannot be correctly recognized. I tried to replace the dollar sign with double dollar sign, but still doesn't work.
How can I do this and make the compilation easy?

All right........
Here is a success experiment in my environment:
C_TMP = $(wildcard *.c)
C_OBJ = $(patsubst %.c,%.o,$(C_TMP))
$(C_OBJ):%.o:%.c
gcc -g -c \$< -o \$#
test: $(C_OBJ)
#echo $(C_OBJ)
And the result is
[shore#shore-82b6 exam]$ make test
gcc -g -c \$main.c -o \$main.o
gcc -g -c \$print.c -o \$print.o
.o .o

Related

How can I pass a rule pattern in a makefile to filter dependencies?

I have a rule in my project to generate libraries from sourcecode. I already have the function to compile %.c to %.o, but I split my library code in multiple source files that begin with the same prefix. I have two separate library code in the same directory, but their source files have different prefixes, that's why I am trying to build a single rule for both (or maybe more) libraries. But I can't pass the prefix of the codebase to the dependencies to filter the object files needed.
The rule I have is this in my Makefile:
# ...
BINDIR = bin
LIBDIR = lib
# ...
# These are all the libraries source files.
LIB_SOURCES = $(wildcard $(LIBDIR)/*.c)
# These are all the libraries "main" source files.
LIB_SRCS = $(filter-out $(wildcard $(LIBDIR)/*_*.c), $(LIB_SOURCES))
# These are all the source files to which I have exported some code from the "main" library source file.
LIB_CODE = $(filter-out $(LIB_SRCS), $(LIB_SOURCES))
# These are all the objects produced by compiling the c source files.
LIB_OBJS = $(patsubst %.c, %.o, $(LIB_CODE))
# ...
# These are all the libraries produced.
LIBS = $(patsubst $(LIBDIR)/%.c,$(BINDIR)/lib%.so,$(LIB_SRCS))
# ...
.PHONY: libs
# ...
%/:
mkdir -p $#
libs: $(BINDIR)/ $(LIBS)
.SECONDEXPANSION:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
#echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $# $^
$(LIBDIR)/%.o: $(LIBDIR)/%.c $(LIBDIR)/%.h
#echo $(CC) $(CFLAGS) -o $# -c $<
For the moment I just print the (incomplete) command, but it still doesn't get the correct output with all the objects needed.
In the directory lib I have the following files:
$ tree lib
lib
├── app.c
├── app_db.c
├── app_db.h
├── app.h
├── app_logic.c
├── app_logic.h
├── app_net.c
├── app_net.h
├── server.c
├── server.h
├── server_queue.c
└── server_queue.h
But it never builds the dependencies correctly.
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o
I have read the following question How to use pattern-dependent variables in dependencies in make pattern rules, which had a tip I thought it would help me, but it didn't.
Any idea how can I achive this?
EDIT 1:
I want the output of the last command to be:
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o lib/app_db.o -c lib/app_db.c
gcc -Wpedantic -O3 -o lib/app_logic.o -c lib/app_logic.c
gcc -Wpedantic -O3 -o lib/app_net.o -c lib/app_net.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o lib/app_db.o lib/app_logic.o lib/app_net.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o lib/server_queue.o -c lib/server_queue.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o lib/server_queue.o
Thanks for your attention.
You added .SECONDEXPANSION, but you didn't escape anything in the prerequisites list so it doesn't actually do anything:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
None of these variables/functions are escaped, so everything here is expanded during the initial read-in, so there's nothing for secondary expansion to do.
The secondary expansion feature consists of two parts: first, you enable it with the special target. Second, you escape the variables and/or functions you want to delay expansion of. So this could be:
getobjs = $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $$(getobjs)
#echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $# $^
Note how we escape the $(getobjs) as $$(getobjs) so that this variable is not expanded until the second pass.
Make isn't very deft with wildcards, and your approach requires it to handle two different wildcards in one line. If that's possible at all, it will be a terrible thing to see. I suggest a different approach.
First, your variables are wrong. It's not clear what your intention was, but here are the ones that fit your desired results:
LIB_SOURCES := $(wildcard $(LIBDIR)/*.c)
LIB_OBJS := $(patsubst %.c,%.o,$(LIB_SOURCES))
Now, you want your makefile to act as if it had these two rules:
$(BINDIR)/libapp.so: $(filter $(LIBDIR)/app%,$(NEW_LIB_OBJS))
#echo build $# somehow from $^
$(BINDIR)/libserver.so: $(filter $(LIBDIR)/server%,$(NEW_LIB_OBJS))
#echo build $# somehow from $^
But rather than spelling them out in the makefile, you want Make to build them at run time. So we'll use a "canned recipe":
define librule
$(BINDIR)/lib$(1).so: $(filter $(LIBDIR)/$(1)%,$(LIB_OBJS))
#echo building $$# somehow from $$^
endef
$(eval $(call librule,app))
$(eval $(call librule,server))
Then rather than writing those last two lines in the makefile, specifying app and server, we can have Make extract them from LIBS:
LIB_NAMES := $(patsubst $(BINDIR)/lib%.so,%,$(LIBS))
$(foreach libname,$(LIB_NAMES),$(eval $(call librule,$(libname))))

Why aren't my variables expanding in my makefile?

I'm using mingw32-make to run my makefile. The contents of the Makefile are the following:
#OBJS specifies which files to compile as part of the project
OBJS = SDLpp.o SDLpp_exception.o SDLpp_window.o
#CC specifies which compiler we're using
CC = g++
#INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS = -IC:\mingw_dev_lib\include\SDL2 \
-IC:\mingw_dev_lib\include\SDL_image \
-IC:\mingw_dev_lib\include\SDLpp
#LIBRARY_PATHS specifies the additional library paths we'll need
LIBRARY_PATHS = -LC:\mingw_dev_lib\lib
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
# -Wall includes all warnings
# -Wl,-subsystem,windows gets rid of the console window
COMPILER_FLAGS = -Wall
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image
#LIB_NAME specifies the name of our library
LIB_NAME = libSDLcpp.a
#This is the target that compiles our executable
all : $(OBJS)
ar rvs $(LIB_NAME) $(OBJS)
%.o : %.c
$(CC) $< $(INCLUDE_PATHS) $(LIBRARY_PATHS) $(COMPILER_FLAGS) -c $(LINKER_FLAGS) -o $#
^(the white-space before the commands are tabs)^
When run, the shell outputs
g++ -c -o SDLpp.o SDLpp.cpp
which indicates that the other variables are not being expanding in the first pattern rule. Oddly, only CC is expanding into g++. Why is this happening?
The issue is not one of non-expanding variables. Rather, the makefile is using the default rule instead of the one you provided.
The reason may be that your rule uses *.c, while you likely have *.cpp files, IIRC.

make: *** No rule to make target - gfortran

I am trying to compile a code -
this code uses a few libraries and for starters I am trying to create a makefile to get one library
I am having difficulties.
this is the makefile
HOME = $(shell pwd)
LIBNA = libbv.a
LIBZP = $(HOME)/$(LIBNA)
# FFLAGC = -Mextend -Msave -g -C -Mchkfpstk -Mchkptr -fpic -Ktrap=fp
FC = gfortran
ifeq ($(OSTYPE),linux)
FC = pgf95 -Msave -fpic
endif
# per il gfortran
FFLAGC = -g -Wall-ffixed-line-length-0 -Mextend -Msave -g -C -Mchkfpstk -Mchkptr -fpic -Ktrap=fp
# FC = gfortran
#
SOURCE = \
filename1.f\
filename2.f\
...
filenamen.f
.SUFFIXES: .f
OBJ = $(SRCS:.f=.o)
.f.o:
$(FC) $(FFLAG) -c $< $#
$(LIBZP): $(LIBZP)($(OBJ))
ar -r $(LIBZP) $?
rm -f $?
this is the makefile I am using.
I get the error
make: *** No rule to make target absolutepath/libbv.a()', needed by
absolute_path/libbv.a'. Stop.
I was wondering if any of you can help
Well, your error message shows this:
absolutepath/libbv.a()
with nothing inside the parentheses. But your makefile has this:
$(LIBZP): $(LIBZP)($(OBJ))
with $(OBJ) in the parentheses. So clearly, $(OBJ) is expanding to the empty string. Why is that?
Well, OBJ is set here:
OBJ = $(SRCS:.f=.o)
based on SRCS. Well, what does that variable contain?
Aha. Nothing, because it's never set. You set this though:
SOURCE = \
...
SOURCE != SRCS, so you're modifying an empty variable and OBJ is the empty string.
I'm not sure why you're prefixing the target with the current directory... that's where it will go by default if you don't specify any directory. In any event, you can use $(CURDIR) rather than running $(shell pwd).
If you're going to use GNU make anyway, I recommend you use pattern rules rather than suffix rules: they're much simpler to read/understand:
%.o : %.f
$(FC) $(FFLAG) -c $< $#
Also don't you need a -o here before $#? I don't use Fortran compilers but I would imagine they work more or less the same as C/C++ compilers.

Makefile not executing to the end

I have the following makefile but it just executes the 1st command where it builds me the .o files and not the .so files. What am I doing wrong?
Thanks,
SHELL = /bin/sh
CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -shared
TARGET = Stepper.so
SOURCES = $(shell echo ./*.c)
HEADERS = $(shell echo ./*.h)
OBJECTS = $(SOURCES:.c=.o)
LIBS = liblua523.a
PREFIX = $(DESTDIR)/usr/local
BINDIR = $(PREFIX)/bin
$(OBJECTS): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
clean:
rm $(OBJECTS)
Unless you specify a different target on the command line, make always builds the first real target found in the makefile. In this case, the first real target is the first object file, so that's all that's built.
This is why you typically see makefiles with a first target of all or similar, which just depends on the various other targets you want built during a standard invocation of "make" with no arguments.
However, your makefile is really not right, in a number of ways. The fact that it's running it all means you actually only have one source file. As soon as you have >1 it will fail.
This:
SOURCES = $(shell echo ./*.c)
is not very efficient; you should use wildcard here:
SOURCES = $(wildcard ./*.c)
This rule:
$(OBJECTS): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
Tells make, "for every object file, if any source file or any header file has changed, recompile it". Basically, it means that if you change ANYTHING in the directory, EVERYTHING will rebuild. If you want that you might as well write a shell script and not bother with make at all.
Further, the compiler will fail when you have >1 source file, as it will try to run:
gcc -g -Wall -c foo.c bar.c -o foo.o bar.o
which is not right.
You don't need to define this rule at all; make has a built-in rule which knows how to build an object file from a source file. Just replace it with this:
$(OBJECTS): $(HEADERS)
(no recipe) so make knows that the objects depend on the headers as well as the source. Note this is not ideal since all objects rebuild if any header changes but it's fine for a simple program.

Get filename without extension within makefile

My makefile looks like this:
SRCS = $(wildcard *.asm)
OBJS = ${SRCS:.asm=.o}
# define a suffix rule for .asm -> .o
.asm.o : $(SRCS)
nasm -f elf $<
all: $(OBJS)
gcc -o ?? $<
^need the name of the target without file extension here ($* is blank)
However, $* is working within .asm.o but is blank within all.
How would I go about setting the gcc output filename to the filename of the object file without any extension?
For example, I want it to execute the following (after the .o file is generated by nasm)
gcc filename filename.o
I think you are looking for
.PHONY: all
all: $(patsubst %.o,%,$(OBJS))
%: %.o
gcc -o $# $<
Your attempt would define a target all which depended on all the object files as if it contained them all; I presume you really want each object file to be independent, and for the all target to depend on them all being made.
(Technically you could now use $* because it is identical to $# in this case, but that's just obscure.)
This is by and large isomorphic to your existing nasm rule, except when there is no suffix, you cannot use the suffix syntax. In other words, your rule is equivalent to
OBJS = $(patsubst %.asm,%.o,$(SRCS))
%.o: %.asm
nasm -f elf $<
The only remaining difference is the .PHONY declaration which just documents that all isn't a file name.
Use VAR = $(basename your_file.ext) <=> $(VAR) = your_file
Let's say that you want to remove .o from test.o
VAR = $(basename test.o)
resulting in $VAR containing "test"
See More Functions Here

Resources