I have the following makefile which is a slight modification on others that I have used in the past. There is an odd issue though with my variable ${CXXOPTS} not being used in the .c.o makefile rule. When I execute the makefile, this is what is executed g++ -c -o SeqPrep2.o SeqPrep2.cpp when I expect this to be executed: g++ -Iseqan-03-02-2012 -c -o SeqPrep2.o SeqPrep2.cpp. (Edit: I solved the problem but see my updated question below about why this makefile worked at all in the first place)
L=-lm -lz
SEQANINC=seqan-03-02-2012
DESTDIR=$(HOME)/
BINDIR=bin
CXXOPTS=-I${SEQANINC}
CXX=g++
A=SeqPrep2
USEROPTS=
O=$(patsubst %.cpp,%.o,$(wildcard *.cpp))
SOURCES=$(wildcard *.cpp)
all: ${A} ${O} ${SOURCES}
install: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${DESTDIR}${BINDIR}/${A} ${O} ${L}
${A}: ${O} ${MYLIBS} ${SOURCES}
${CXX} ${USEROPTS} -o ${A} ${O} ${L}
clean::
rm -f ${A} ${O}
.c.o:
${CXX} ${CXXOPTS} ${USEROPTS} -c $< -o $#
check-syntax:
${CXX} ${CXXOPTS} ${USEROPTS} -c -o .nul -S ${CHK_SOURCES}
UPDATE:
I changed .c.o to .cpp.o. Is this a case of gnu make guessing that when I asked for a .o file in one of my rules, that it should make it just by running g++ -c -o SeqPrep2.o SeqPrep2.cpp even though I didn't tell it to do that? I guess that is my new question, why did the above makefile work at all, and why did it have the odd behavior I observed. One thing to note is that even though it didn't come though in the formatting, there is a lot of white space between the g++ and the -c, kind of like it was trying to put in my variables, but it didn't. That is partially what originally lead me to believe that it was seeing my rule at all, even though it seems like it didn't now. Thanks for helping me understand how this stuff works.
You've got the rule .c.o but you're compiling cpp files, when I use .cpp.o: it works great! With files: me.cpp us.cpp you.cpp
I get:
Building file me.cpp
g++ -Iseqan-03-02-2012 -c me.cpp -o me.o
Building file us.cpp
g++ -Iseqan-03-02-2012 -c us.cpp -o us.o
Building file you.cpp
g++ -Iseqan-03-02-2012 -c you.cpp -o you.o
g++ -o SeqPrep2 me.o us.o you.o -lm -lz
Related
I have designed a Makefile that compiles all the .c files individually and produces a .o respectively (I think this happens Implicitly and works perfectly fine).
The executable (.out) is not being generated from the .o files.
Makefile:
TARGET = all.out
OBJS = file1.o file2.o file3.o
CC = gcc
CFLAGS = -g -Wall
all : $(TARGET)
$(TARGET) : $(OBJS)
# gcc $^ -o $#
run : $(TARGET)
./$<
clean :
rm -rf *.o $(TARGET)
Output:
$ make
make: Circular all.out <- all dependency dropped.
gcc -g -Wall -c -o file1.o file1.c
gcc -g -Wall -c -o file2.o file2.c
gcc -g -Wall -c -o file3.o file3.c
cp file1.o all.out
Note: The Makefile works perfectly and produces the perfect results if the line no. 7 present in it is uncommented.
line no. 7:
# gcc $^ -o $#
Output when line no. 7 is uncommented (Works perfectly as intended):
gcc -g -Wall -c -o file1.o file1.c
gcc -g -Wall -c -o file2.o file2.c
gcc -g -Wall -c -o file3.o file3.c
gcc file1.o file2.o file3.o -o a.out
I am new to Makefiles.
Queries:
why does commenting line no. 7 causing this issue and uncommenting it works perfectly?
What is cp in the first output when line no.7 was commented?
What does circular - dependency dropped mean?
I can't explain how you are seeing the problem you showed to us. Either what you wrote above is not actually what you're using, or you have a buggy version of GNU make. I can't reproduce the behavior you're seeing.
But, I'm sure it's related to this: GNU make has a built-in rule that knows how to build an xx.out file from a file xx for any xx:
# make -p -f/dev/null
...
%.out: %
# recipe to execute (built-in):
#rm -f $#
cp $< $#
If you comment out your own recipe as an explicit rule, then make will search for one among the pattern rules it knows about and it will find this built-in pattern rule.
However this rule shouldn't match based on what you've shown us: in order for it to match with a target of a.out, make would have to find or know how to build a target a and that doesn't seem to be available. Also, knowing how to build a would show a circular dependency on a.out.
If your makefile was:
TARGET = all.out
THEN it would all make perfect sense because you would have:
all : all.out
all.out : file1.o file2.o file3.o
and after the implicit rule match %.out: % it would expand like this:
all : all.out
all.out : all file1.o file2.o file3.o
#rm -f all.out
cp all all.out
So I assume that when you copied the output into your question you changed it: best to not do that. You should post exactly the problem you have (and verify you still have the problem with what you posted).
Im a Windows dev who has no expirience on building C/C++ programs on Linux, but now I need to. Right way would be to go and learn Make and g++ compiler, but before I commit to that I want to figure out some basic stuff.
So I have .c program which is compiled with this makefile:
CUDA_VER=11.5
ifeq ($(CUDA_VER),)
$(error "CUDA_VER is not set")
endif
APP:= deepstream-test3-app
TARGET_DEVICE = $(shell gcc -dumpmachine | cut -f1 -d -)
NVDS_VERSION:=6.0
LIB_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/
APP_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/bin/
ifeq ($(TARGET_DEVICE),aarch64)
CFLAGS:= -DPLATFORM_TEGRA
endif
SRCS:= $(wildcard *.c)
$(info info is $(SRCS))
INCS:= $(wildcard *.h)
PKGS:= gstreamer-1.0
OBJS:= $(SRCS:.c=.o)
CFLAGS+= -I../../../includes \
-I /usr/local/cuda-$(CUDA_VER)/include
CFLAGS+= $(shell pkg-config --cflags $(PKGS))
LIBS:= $(shell pkg-config --libs $(PKGS))
LIBS+= -L/usr/local/cuda-$(CUDA_VER)/lib64/ -lcudart -lnvdsgst_helper -lm \
-L$(LIB_INSTALL_DIR) -lnvdsgst_meta -lnvds_meta \
-lcuda -Wl,-rpath,$(LIB_INSTALL_DIR)
$(info info is $(CFLAGS))
all: $(APP)
%.o: %.c $(INCS) Makefile
gcc -c -o $# $(CFLAGS) $<
$(APP): $(OBJS) Makefile
gcc -o $(APP) $(OBJS) $(LIBS)
install: $(APP)
cp -rv $(APP) $(APP_INSTALL_DIR)
clean:
rm -rf $(OBJS) $(APP)
First thing I tried is to change this Makefile to compile it as C++ program. I changed .c file into .cpp, in makefile I change gcc to g++ everywhere and .c to .cpp everywhere. It gave me error that it couldnt find "main" entry point.
I gave up on that pretty fast and decided just to use lines output of original makefile, ending up with this:
g++ -c -o deepstream_test3_app.o -I../../../includes -I /usr/local/cuda-11.5/include -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include ./deepstream_test3_app.cpp
g++ -o deepstream-test3-app deepstream_test3_app.o -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -L/usr/local/cuda-11.5/lib64/ -lcudart -lnvdsgst_helper -lm -L/opt/nvidia/deepstream/deepstream-6.0/lib/ -lnvdsgst_meta -lnvds_meta -lcuda -Wl,-rpath,/opt/nvidia/deepstream/deepstream-6.0/lib/
First question, can I combine this 2 launches of g++ into one?
Second, when I make changes to "./deepstream_test3_app.cpp" they are not noticed by compiler. I added
#include <iostream>
...
std::cout << "hello!" << std::endl;
and they are ignored. Its like g++ gets as input some other copy/older version of the file and I dont understand how to go about it.
Hope for any help, sorry if it's all sounds stupid.
Ignoring for the moment the issues surrounding compiling C code with a C++ compiler,
g++ -c -o deepstream_test3_app.o -I../../../includes -I /usr/local/cuda-11.5/include -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include ./deepstream_test3_app.cpp
g++ -o deepstream-test3-app deepstream_test3_app.o -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -L/usr/local/cuda-11.5/lib64/ -lcudart -lnvdsgst_helper -lm -L/opt/nvidia/deepstream/deepstream-6.0/lib/ -lnvdsgst_meta -lnvds_meta -lcuda -Wl,-rpath,/opt/nvidia/deepstream/deepstream-6.0/lib/
First question, can I combine this 2 launches of g++ into one?
Yes. It is a common practice in makefiles to separate the compilation and linking steps, but that is not mandatory. When there are multiple sources, the separation makes it possible to limit recompilations to only the source files that have changed, but it doesn't make much difference, makefile or not, when there is only one source file.
The one-command version would be mostly a concatenation of the two commands you gave. One would omit the -c option, which instructs g++ to compile but not link, and one would omit the -o deepstream_test3_app.o, which specifies the name of the object file that we are no longer going to create. One would also omit the appearance of deepstream_test3_app.o drawn from the link (second) command, as we are going straight from source file to program. The rest of the options can be reordered to some extent, but all the -l options need to remain in the same order relative to each other and to any object files among the inputs. Here is how I would write it:
g++ -c -o deepstream_test3_app -I../../../includes -I /usr/local/cuda-11.5/include -pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -Wl,-rpath,/opt/nvidia/deepstream/deepstream-6.0/lib/ ./deepstream_test3_app.cpp -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -L/usr/local/cuda-11.5/lib64/ -lcudart -lnvdsgst_helper -lm -L/opt/nvidia/deepstream/deepstream-6.0/lib/ -lnvdsgst_meta -lnvds_meta -lcuda
Second, when I make changes to "./deepstream_test3_app.cpp" they are not noticed by compiler.
The compiler compiles the source file(s) you tell it to.
Its like g++ gets as input some other copy/older version of the file
It is possible that you are indeed telling it to compile a different version than the one you modified. It is also possible that compilation fails, so you don't get a new executable. And it is possible that when you try to run the result, you are not running the program you think you are running. We don't have enough information to know.
With regard to the last, however, do be aware that on Linux, unlike on Windows, the working directory is not automatically in the executable search path. If you want to run the compiled result from the above command, you would want to specify the path to it, which you could most easily do by prepending ./ to its simple name: ./deepstream-test3-app.
i thought it would be easy but i can't actually figure out nor find on internet, a solution to advertise "compilation of the objects file" (for instance) just before compiling, and avoiding relink in the same time
my makefile would be something like this :
libfrog.a: $(OBJS)
#echo "building the library"
ar -rc $# $^
%.o:%.c
gcc -i. -c -o $# $<
which produce, when prompt "make" :
gcc -I. -c -o file01.o file01.c
gcc -I. -c -o file02.o file02.c
gcc -I. -c -o file03.o file03.c
gcc -I. -c -o file04.o file04.c
gcc -I. -c -o file05.o file05.c
building library
ar -rc libfrog.a file01.o file02.o file03.o file04.o file05.o
but i would like to have :
compilation of the objects files
gcc -I. -c -o file01.o file01.c
gcc -I. -c -o file02.o file02.c
gcc -I. -c -o file03.o file03.c
gcc -I. -c -o file04.o file04.c
gcc -I. -c -o file05.o file05.c
building library
ar -rc libfrog.a file01.o file02.o file03.o file04.o file05.o
now :
1 - if i put an echo before the rule libfrog.a is called (say by creating another first rule), it will print even if i prompt "make" two times and nothing is to be done...
2 - if i put an echo in the rule %.o:%.c it will print for each file
3 - if i put an echo as a dependency of the first rule it will force to relink all the files when prompt "make" again, even when just one file has been modified libfrog.a: echo $(OBJS) (and a rule "echo" which echo the text)...
so I've tried to echo for each compilation but with changing the text to echo nothing, i failed... i tried to create an echo.txt file just to create a rule that would depend on its existence but i failed too. I have no idea if it's possible ?
It's not really simple to do. But if you're using GNU make you can do it with the help of order-only prerequisites:
%.o : %.c | announce
gcc -I. -c -o $# $<
.PHONY: announce
announce:
echo "compilation of the objects files"
Personally I don't think showing this message is needed and I wouldn't add even the above amount of complexity to support it in my makefiles.
But if you really want to do it and you don't want the message to be printed unless some object file needs to be made, you'll have to get really fancy and do something like this:
PRINTED :=
%.o : %.c
$(or $(PRINTED),$(eval PRINTED := :)echo "compilation of the objects files")
gcc -I. -c -o $# $<
Once it's working you'll want to add a # before the first recipe line.
First, I should admit makefiles are something that I'm very inexperienced at, so I apologize if this is an error that I should have been able to solve myself, but I have spent several hours on this, including reading the various answers on this site, and have been unable to discover a solution.
With that said, I have created the following makefile to compile my code on a Linux machine; it completes the sub compilations just fine, but when it comes to making the output itself, xPlatST, it throws an error.
g++ -std=c+=11 -g -Wall -pthread -c -o xPlatST.o xPlatST.cpp
g++ -std=c+=11 -g -Wall -pthread -c -o stdafx.o stdafx.cpp
g++ -std=c+=11 -g -Wall -pthread -c xPlatST xPlatST.o stdafx.o -L../hwloc
g++ error: xPlatST: No such file or directory
make: *** [xPlatST] Error 1
I believe it seems to think that the xPlatST is one of it's compilation files and thus can't find it, but for the life of me I can't work out why.
hwloc is a third party library, and should be unrelated to this issue. The code compiles just fine when compiled from the command line directly.
My files are xPlatST.cpp, xPlatST.h, stdafx.cpp, stdafh.h
Code is as follows:
CXX = g++ -std=c++11
INCLUDES =
LIBS = -L../hwloc
CXXFLAGS = -Wall -g -pthread
OBJS = xPlatST.o stdafx.o
xPlatST: ${OBJS}
${CXX} ${CXXFLAGS} ${INCLUDES} -c $# ${OBJS} ${LIBS}
clean:
-rm xPlatST *.o
Any help would be greatly appreciated; thank you in advance.
Your assumption is correct. Your recipe is trying to use xPlatST as a source. Change the -c into a -o in your rule:
${CXX} ${CXXFLAGS} ${INCLUDES} -o $# ${OBJS} ${LIBS}
The -c flag tells the compiler to take all files, compile, and assemble them into an object file (.o). The -o flag specifies the destination file.
In my Makefile I have a rule to compile Fortran source files, like so
.SUFFIXES:
%.o: %.[fF]
$(FC) $(FFLAGS) -c $< -o $#
This has worked fine on several machines. When I tried it on another machine (incidentally with a newer (GNU) make, 3.82 instead of 3.81), it did not work, and I had to replace it with two separate rules for .f and .F.
The wildcard works without the %, i.e. this works:
.SUFFIXES:
test.o: test.[fF]
$(FC) $(FFLAGS) -c $< -o $#
What is going on?
I can fully reproduce the behavior here. It is a regression in make 3.82. The discussion attached to the bug report suggests using .SECONDEXPANSION to work around the problem. I've tried it and got it to work in a simple test setup:
.SUFFIXES:
.SECONDEXPANSION:
%.o: $$(wildcard %.[fF])
$(FC) $(FFLAGS) -c $< -o $#
Using the file above and two test files named test.f and test2.F, here's a couple commands I issue and the output produced by the Makefile:
$ make -n test2.o
f77 -c test2.F -o test2.o
$ make -n test.o
f77 -c test.f -o test.o
The workaround works both with 3.81 and 3.82.