makefile - how to exclude file extension suffix from a variable - c

the next makefile receive the file to compile from its command line arg -ARGS. For example
make ARGS="out.c"
I would like to replace the name of the created executable "run" with the variable ARGS excluding the suffix
in this example : run="out"
all: Task1
Task1: outputs/output.o
gcc -g -m32 -Wall -o run outputs/output.o
outputs/output.o: outputs/${ARGS}
gcc -m32 -g -w -Wall -ansi -c -o outputs/output.o outputs/${ARGS}
.PHONY: clean
run: clean Task1
clean:
rm -f outputs\output.o Task1

The crude way to do what you ask is simply:
EXEC := $(basename $(ARGS))
all: Task1
Task1: outputs/output.o
gcc -g -m32 -Wall -o $(EXEC) outputs/output.o
A better way is:
EXEC := $(basename $(ARGS))
all: $(EXEC)
$(EXEC): outputs/output.o
gcc -g -m32 -Wall -o $(EXEC) outputs/output.o
Better still:
EXEC := $(basename $(ARGS))
all: $(EXEC)
$(EXEC): outputs/output.o
gcc -g -m32 -Wall -o $# $^

If using GNU make you need the basename function, perhaps as $(basename $(AUX)). Maybe variables like $(*F) might be useful too (please read the documentation). However, your Makefile is probably wrong.
I can't suggest an improvement, because what you want to do and to happen is unclear.
BTW, use remake (as remake -x) or at least make --trace (with a recent enough GNU make 4.x) to understand what make is doing and why.
Also, you'll find several examples of Makefile-s: here & there
etc... Don't forget that make has a many builtin rules, you'll get them by running make -p
You won't lose your time by reading the documentation of GNU make, and some tutorials, and some examples of Makefile-s.

Related

GNU Makefile : How to use pattern-rule adding a compilation flag to a match-anything pattern-rule by using pattern-specific variable value?

I have created several test files test_*.c, each testing a single function of a c library I built.
I first wrote a Makefile for compiling each c file to produce its corresponding binary:
TEST_SRCS = ${wildcard *.c}
TEST_EXECS = ${TEST_SRCS:.c=}
PROJECT_PATH = ../my_project
CFLAGS = -Wall -Wextra -Werror
%:: %.c ${PROJECT_PATH}/libmyproject.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
all: ${TEST_EXECS}
clean:
rm -f ${TEST_EXECS}
re: clean all
.PHONY: all clean re
This works as expected, so when i type make test_<name_of_my_function> and if the 'test_<name_of_my_function>.c' file exists, it compiles it to create the 'test_<name_of_my_function>' binary.
But now i want to add a rule that creates the binary in debug mode by adding the gcc flag -g to the command if i run the command make debug_test_<name_of_my_function>.
I tried adding the pattern-specific rule debug_% and use a pattern-specific value for appending -g to CFLAGS:
TEST_SRCS = ${wildcard *.c}
TEST_EXECS = ${TEST_SRCS:.c=}
PROJECT_PATH = ../my_project
CFLAGS = -Wall -Wextra -Werror
%:: %.c ${PROJECT_PATH}/libmyproject.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
all: ${TEST_EXECS}
debug_%: CFLAGS += -g
debug_%: %
clean:
rm -f ${TEST_EXECS}
re: clean all
.PHONY: all clean re
But when i run for example debug_test_function1, i get the following ouptut :
make: *** No rule to make target 'debug_test_function1'. Stop.
Note that whatever prerequisite rule i use for the target debug_%, it isn't executed (even if the prerequisite is not a pattern rule).
Note also that if i replace in the makefile
debug_%: CFLAGS += -g
debug_%: %
by
debug%: %.c ${PROJECT_PATH}/libft.a
gcc ${CFLAGS} -g $< -L${PROJECT_PATH} -lmyproject -o $#
it works. But i'd lose the benefit of using a pattern-specific variable here.
Any clue oh how to use pattern-specific variable values to do it?
Thank you for your help !
This:
debug_%: %
does not define a pattern rule. It deletes a pattern rule. See the GNU make manual. So, you've not defined any rules here that know how to build debug_test_function1 (because there's no file debug_test_function1.c to build it from and the only rule you have available is the match-anything rule).
You have to provide the recipe here, you cannot omit it. But obviously you can still add a pattern-specific variable; why not?:
debug_%: CFLAGS += -g
debug_%: %.c ${PROJECT_PATH}/libft.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
I'm not really sure what "benefit of pattern-specific variables" you are referring to since you don't seem to build an other prerequisites that need to inherit the pattern-specific variable. But the above should work.

How to make a proper C makefile

so far I have learned this kind of makefile :
finalcode : code.o
gcc -g -ansi -Wall -pedantic code.o -o finalcode
code.o : code.c
gcc -c -ansi -Wall -pedantic code.c -o code.o
I'm interested in learning the better version
all:
clean:
etc..
where can I learn how to write a more "professional" makefile?
thanks in advance!
So you just want the typical "phony" targets? That's simple, make all the first rule (so it's the default) and have it depend on anything you want to have built, e.g.:
all: finalcode
Then, in clean, just write a script to delete whatever should be cleaned, e.g.:
clean:
rm -f *.o
Finally, don't forget to make these rules "phony", so make knows they don't actually create files with these names:
.PHONY: all clean
Done.
As for "professional", that's quite subjective, but I'd start by defining variables for the compiler (CC), flags (CFLAGS), includes and so on and use these. If you are fine with a bit loss of portability, use pattern rules e.g. for creating the object files like
%.o: %.c
$(CC) -c -o$# $(CFLAGS) $(INCLUDES) $<

No debugging symbols found in ArchLinux with -g

I have a problem with GDB in Archlinux:
Even I add -g in my Makefile gdb say (no debugging symbols found)...done..
But if I compile manually gcc -g *.c it work...
I don't know what is don't work in my Makefile ?
My Archlinux:
Linux sime_arch 4.13.4-1-ARCH #1 SMP PREEMPT Thu Sep 28 08:39:52 CEST 2017 x86_64 GNU/Linux
My GCC:
gcc version 7.2.0 (GCC)
My Makefile:
SRC = test.c \
test2.c
OBJ = $(SRC:.c=.o)
NAME = test_name
CFLAG = -Wall -Werror -Wextra
all: $(NAME)
$(NAME): $(OBJ)
gcc -g $(OBJ) -o $(NAME) $(CFLAG)
clean:
rm -f $(OBJ)
fclean: clean
rm -f $(NAME)
re: fclean all}
Thanks in advance
You are adding the -g only to the linking command. The object files are generated by the auto compile target of make. This doesn't have the -g flag in it.
You have 2 options -
Change your variable CFLAG to CFLAGS and add -g to it. CFLAGS is picked by the auto compile command and it will create object files with debug info
Add the following target -
%.o: %.c
gcc -g $(CFLAG) -o $# $<
before the $(NAME) target.
The second one gives you more control with the targets but the first method is the standard way of compiling.
Also, always try using standard names for variables unless you specifically need to name them separately.

GCC exiting with an error 1 even with -Wall. No explanation why?

So I tried to recompile one of my projects from a few weeks ago and to my surprise I keep receiving an error one on it. I used MinGW to compile it originally and Eclipse CDT. I have -Wall flag enabled on GCC so I assumed if it was a problem with the code I would have a more useful information than a make error 1 being thrown. As such, I suspect that the issue could lie in how I formatted the make file. Luckily, I did compile the project when I push the commits last time and the binaries are still in the repo. Nevertheless, I would appreciate some help so that I can continue to improve
the project.
Edit: when I do -all, it just refuses to compile.
Here is the makefile. I hope it is a simple as me following some incorrect syntax:
CC=gcc -I../Include -L..\Lib
override CFLAGS+=-Wall -O3 #$(shell pkg-config --cflags fftw3)
#override LDFLAGS+=#$(shell pkg-config --libs fftw3 glib-2.0) -lm
.PHONY: all clean
all: lvdoenc lvdodec
lvdoenc: lvdoenc.o lvdomain.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS) -I../Include -L../Lib -lfftw3
lvdodec: lvdodec.o lvdomain.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS) -I../Include -L../Lib -lfftw3
%.o: %.c
$(CC) -c $(CFLAGS) -o $# $^
lvdoenc.c: lvdocommon.h
lvdodec.c: lvdocommon.h
clean:
rm -f lvdoenc lvdodec lvdomain.o lvdoenc.o lvdodec.o
Here is a link to my repo:
https://github.com/Skylion007/LVDOWin
Update: Using some of the answers I have confirmed that it is GCC that is exiting with an error 1 and I cannot figure out why.
Update2: It's not printing anything to syserr.
Without a transcript of make's output, when you run it, I can't see why GCC should fail silently, but I can see at least two problems with your makefile:
Since you state that you are using MinGW, your target platform must be MS-Windows, on which executable files should be qualified by a .exe extension; thus, your all: lvdoenc lvdodec rule is malformed; it should, at the very least be all: lvdoenc.exe lvdodec.exe[1], (or better, for portability all: lvdoenc$(EXEEXT) lvdodec$(EXEEXT), where you define EXEEXT = .exe for Windows, and leave EXEEXT undefined, or defined to be nothing, for platforms which don't require the extension).
Your two rules lvdoenc.c: lvdocommon.h and lvdodec.c: lvdocommon.h are obviously incorrect; the .c files don't depend on the .h, but their respective .o files do. Thus, these two rules should be lvdoenc.o: lvdocommon.h and lvdodec.o: lvdocommon.h respectively.
[1] Of course, you then also need to correctly refer to these two "goals" respectively, as lvdoenc.exe and lvdodec.exe, (or lvdoenc$(EXEEXT) and lvdodec$(EXEEXT)), consistently, throughout the makefile.
There are a few other constructs, within your makefile, which I consider questionable: CC shouldn't really be defined, with the -I../Include or -L..\Lib, (and why inconsistently / in the former, but \ in the latter? Both should be /). Conventionally, -I ... belongs in CPPFLAGS, and -L ... in LDFLAGS, with both CFLAGS and CPPFLAGS passed to the compiler, and normally all of CFLAGS, CPPFLAGS, and LDFLAGS passed to the compiler driver, when invoking the linker, (although, as others have noted in comments, the -I ... settings are strictly necessary when compiling .c to .o, while the -L ... settings are required only in the linking phase).
the following makefile is more in line with what you need for your project.
However, it does not use:
#$(shell pkg-config --libs fftw3 glib-2.0)
which you will need to re-add.
notice the usage of ':=' when defining macros, so the macro only needs to be evaluated once, rather than every time it is referenced.
the paths for the SHELL macro and the CC macro may need to be modified for your system.
SHELL := /usr/bin/sh
CC := /usr/bin/gcc
#CFLAGS := -c -Wall -Wextra -pedantic -std=c99 -O3 #$(shell pkg-config --cflags fftw3)
CFLAGS := -c -Wall -Wextra -pedantic -std=c99 -O3
# override LDFLAGS+=#$(shell pkg-config --libs fftw3 glib-2.0) -lm
LDFLAGS :=
SRCS := $(wildcard *.c)
ENCOBJS := lvdoenc.o lvdomain.o
DECOBJS := lvdodec.o lvdomain.o
.PHONY: all clean
all: lvdoenc lvdodec
lvdoenc: $(ENCOBJS)
$(CC) $(LDFLAGS) -o $# $(ENCOBJS) -L../Lib -lfftw3 -lm
lvdodec: $(DECOBJS)
$(CC) $(LDFLAGS) -o $# $(DECOBJS) -L../Lib -lfftw3 -lm
%.o:%.c lvdocommon.h
$(CC) -c $(CFLAGS) -c $< -o $# -I../Include
clean:
rm -f lvdoenc lvdodec lvdomain.o lvdoenc.o lvdodec.o
Apparently, all that was the cause was that I had uninstalled the 64bit version of MinGW and tried to switch to the 32bit version of MinGW. Unfortunately, some of the libraries would not compile in the 32bit version so I just used MinGW-w instead to solve this problem. It turns out GCC was not starting due to a linker error, but this error was not proportionating and could not be discovered until I tried to run it from the Windows terminal. I am still in the process of solving it and will update this answer when I have fully solved the issue.
Had the same problem while tried to compile my project with make from MSys. Accidentally problem had been solved, after I added a quotes to gcc input and output files in the makefile. I don't know how it works, but hope that it will help someone else.
So in the TS example code should look like this
%.o: %.c
$(CC) -c $(CFLAGS) -o "$#" "$^"
PS: had no problems with building project from ubuntu terminal though, so maybe it's just a msys problem.

A Makefile with Multiple Executables

I am trying to write a makefile which uses macros to create multiple executables from multiple files at once. I tried searching through previously answered questions but, because I am fairly new to programming in C as well as working with gcc, I was not able to find an answer to my question.
Here is what I have so far:
CC=gcc
CFLAGS=-I.
OBJ = ex1.c ex3.c
EXECUTABLE = ex1 ex3
$(EXECUTABLE): $(OBJ)
gcc -o $# $^ $(CFLAGS)
clean:
rm -f $(EXECUTABLE)
I would like the line
$(EXECUTABLE): $(OBJ)
to create executables ex1 and ex3 from files ex1.c ex3.c respectively.
For this particular case, where each executable has a single source file with .c extension, all you need is a one line Makefile:
all: ex1 ex3
The built-in default rules for make then work already:
$ make
cc -O2 -pipe ex1.c -o ex1
cc -O2 -pipe ex3.c -o ex3
Behind the scene, make is using the POSIXly mandated built-in single suffix rule
.c:
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $<
Vary the command to your liking with make CC=gcc CFLAGS=-O2 LDFLAGS=-s and similar.
Trivia of the day: in fact, if you are willing to name the targets when invoking make, you can use an empty or even run without any Makefile:
$ make -f /dev/null CC=gcc CFLAGS=-O2 LDFLAGS=-s ex1 ex3
gcc -O2 -s ex1.c -o ex1
gcc -O2 -s ex3.c -o ex3
$ rm -f Makefile ex1 ex3
$ make CC=gcc CFLAGS=-O2 LDFLAGS=-s ex1 ex3
gcc -O2 -s ex1.c -o ex1
gcc -O2 -s ex3.c -o ex3
Make magic!
As a rule of thumb, don't reinvent the wheel (or rules), use the rules that are already there. It simplifies your and make's life a lot. This makes for small and sexy makefiles to impress the ladies with :-)
Some suggestions (assuming you use GNU make, not something else)
First, run once make -p, you'll understand what builtin rules make is knowing. Look in particular for COMPILE.c and LINK.c
Then, I suggest
CFLAGS= -g -Wall -I.
(because you really want -g for debugging, and -Wall to get most warnings)
And you probably don't need
$(EXECUTABLE): $(OBJ)
gcc -o $# $^ $(CFLAGS)
However, I suggest adding before most other rules
.PHONY: all clean
all: $(EXECUTABLES)
Actually, I would code your Makefile (for GNU make!) as follow
# file Makefile
CC= gcc
RM= rm -vf
CFLAGS= -Wall -g
CPPFLAGS= -I.
SRCFILES= ex1.c ex2.c ## or perhaps $(wildcard *.c)
OBJFILES= $(patsubst %.c, %.o, $(SRCFILES))
PROGFILES= $(patsubst %.c, %, $(SRCFILES))
.PHONY: all clean
all: $(PROGFILES)
clean:
$(RM) $(OBJFILES) $(PROGFILES) *~
## eof Makefile
Remember that tab is a significant character in Makefile-s (action part of rules). In this answer, lines starting with four spaces at least should really start with a tab character.
Once everything is debugged consider running make clean to clean everything, and then make -j CFLAGS=-O2 all to compile in parallel everything with optimizations.
At last, I recommend using remake and running remake -x to debug complex Makefile-s
Of course, I'm supposing that your directory has only single-file programs.
BTW, there are other build automation tools. Perhaps you might consider using omake or ninja. For building large programs (millions of source code lines) consider also automake, ccache, cmake, icecream. In some cases, consider generating some C code with GPP, GNU bison, SWIG, etc... or using your own Python or Guile script (or C meta-program). See also this draft report.
Don't forget to use a version control system like git for your source files. It is also time to learn such a tool.
The following answer includes multiple executable such as initiate, process1, process2, ..., process4.
LOCAL_INCLUDE=./
all: clean process_first process_second init
process_first:
gcc -g -o process1 -I$(LOCAL_INCLUDE) process1.c -lzmq -L. -L./.
gcc -g -o process2 -I$(LOCAL_INCLUDE) process2.c -lzmq -L. -L./.
process_second:
gcc -g -o process3 -I$(LOCAL_INCLUDE) process3.c -lzmq -L. -L./.
gcc -g -o process4 -I$(LOCAL_INCLUDE) process4.c -lzmq -L. -L./.
init:
gcc -g -o initiate -I$(LOCAL_INCLUDE) initiate.c -lzmq -lconfig -lpthread -L. -L./. -ldl -lrt
clean:
rm -rf init_manager.o init_manager
rm -rf process1 process2 process3 process4
NOTE: It is a good practice to clean and touch all the executable files before making them again.
You're close, but you need a pattern rule:
$(EXECUTABLE): % : %.c
And then a default rule to make it build both:
all: $(EXECUTABLE)

Resources