makefile explicitly linking multiple dynamic libraries - makefile

I'm trying to put together a simple makefile example like so:
FLAGS = -std=c++14
INC= -I/usr/local/include
LI = -L/usr/local/lib
LIB = /usr/local/lib/
LIBS = $(LIB)libboost_filesystem-mt.a \
$(LIB)libboost_filesystem-mt.dylib \
$(LIB)libboost_filesystem.a \
$(LIB)libboost_filesystem.dylib \
$(LIB)libboost_system-mt.a \
$(LIB)libboost_system-mt.dylib \
$(LIB)libboost_system.a \
$(LIB)libboost_system.dylib
default:
g++ main.cpp $(FLAGS) $(INC) $(LI) $(LIBS) -o assemble
./assemble
clean:
rm assemble
Is there a way to not have to prepend $(LIB) so many times? That's the only way I can get this to work right now (the above doesn't).

If you want the linker to search the path you have to add libraries using the -l flag. So instead of adding libboost_system-mt.a to your link line, you have to add -lboost_system-mt to your link line. Then the linker will search the paths provided by -L.
I'm not sure about the dylib stuff; I don't do much with OS X.
In any event, if you're using GNU make you can do this:
LIBNAMES := filesystem-mt filesystem system-mt system
LIBS := $(foreach N,$(LIBNAMES),$(LIB)libboost_$N.a $(LIB)libboost_$N.dylib)

Related

How to link a lot of file .mod .o in GCC

i tried to compile without makefile with equations.com gcc
i have bunch of f90, and lib.a
Since a lot of files, i can't use like gfortran *.f90 *.f so i am using gfortran -c filename.f90 each in a batch file.
This create alot of .mod files and .o files.
[code]
gfortran -c -I INCLUDE -O3 -ffast-math -march=znver3 ALLOCATED_ARRAY_DATA.f90
gfortran -c -I INCLUDE -O3 -ffast-math -march=znver3 ALLOCATED_MEMORY.f90
gfortran -c -I INCLUDE -O3 -ffast-math -march=znver3 ALLOCATED_MEMORY_Interface.f90
[/code]
How to link it to exe with ld with several file?
[code]
ld #"names.rsp"
[code]
that names.rsp contains
[code]
../superlu/lib/superlu.a \
../superlu/src/c_fortran_dgssv.o \
../superlu/lib/libopenblas.a \
ALLOCATED_ARRAY_DATA.o \
ALLOCATED_MEMORY.o \
ALLOCATED_MEMORY_Interface.o \
/o mys.exe
[/code]
I think better to study cross-compiling-linking using CMAKE and building using jom or make, than to do it manual.

Im trying to compile program on Ubuntu and dont understand some things

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.

Makefile g++ lrt problem. Cannot find lrt

Here is my makefile.
# The intuitive "all" target will be our default.
.DEFAULT_GOAL := all
# Component dir's to search and invoke make.
# (Try preserving the order of directories)
COM := src_dir1 src_dir2 src_dir3
PROJ_DIR = $(shell pwd)
EXEC := anonymousforconfidentiality
CC := g++
CFLAGS := -g3
LIBS = `pkg-config --cflags --libs glib-2.0 gio-unix-2.0 bluez protobuf lrt`
.PHONY : clean compile link all
all: | clean compile link
link:
$(eval $#_ALLOBJECTS := $(shell find . -name '*.o'))
$(CC) $(CFLAGS) -o $(EXEC) $($#_ALLOBJECTS) $(LIBS)
compile:
for COMDIR in $(COM) ; do \
$(MAKE) INCLUDE_PATH=$(PROJ_DIR) -C $$COMDIR ; \
done
clean:
for COMDIR in $(COM) ; do \
rm -f $$COMDIR/bin/*.o ; \
done
rm -f $(EXEC)
I am not able to link the library 'lrt'. I make extensive use of POSIX real time such as mq_open(), mq_send(), mq_receive() etc... So it is imperative I link it.
Some of the variations I tried:
1. librt
2. lrt
3. rt
4. librt-dev
However I always get this error:
Package lrt was not found in the pkg-config search path.
Perhaps you should add the directory containing `lrt.pc'
to the PKG_CONFIG_PATH environment variable
No package 'lrt' found
I even tried to manually install "librt" but was unsuccessful in locating the package. Nor did apt-get find it.
I was assuming this lib comes prepackaged with Ubuntu normal kernel (no real time patch). Need help with resolution of this issue.
You probably want to link rt library. This is done with -lrt. No need to use pkg-config for it.
E.g.:
LIBS := `pkg-config --libs glib-2.0 gio-unix-2.0 bluez protobuf` -lrt

Error while loading shared libraries: liblua.so

I'm trying to launch a client for a school project that has an AI developed in Lua, I have added liblua.so in a /lib/ folder at the root of my program's folder.
After compiling and launching said program, I get the following error:
./zappy_ai: error while loading shared libraries: liblua.so: cannot open shared object file: No such file or directory
From what I understand I must do something at the compilation for my program to know where my shared library is located.
Here's the relevant part of my Makefile:
CXX = g++
BASE_FLAGS = -Wall -Wextra -Iincludes
AI_NAME = zappy_ai
AI_PATH = ./sources/client/
AI_FLAGS = $(BASE_FLAGS) \
-L./lib/ \
-I./includes/client/ \
-I./include/ \
-std=c++11 \
AI_LDFLAGS = -llua
AI_SRCS = main.cpp \
Client.cpp \
Params/Params.cpp \
Params/Option.cpp \
SocketTCP.cpp \
Misc/Error.cpp
AI_OBJS = $(addprefix $(AI_PATH), $(AI_SRCS:.cpp=.cpp.o))
%.cpp.o : %.cpp
#printf "%b[Compilation]%b %-50s" $(BLUE) $(RESET) $<
#$(CXX) $(FLAGS) -c $< -o $#
#printf "%bOK%b\n" $(GREEN) $(RESET)
$(AI_NAME) : FLAGS = $(AI_FLAGS)
$(AI_NAME) : $(AI_OBJS)
#$(CXX) $^ -o $# $(AI_LDFLAGS)
#printf "%b[Message]%b AI compilation done\n\n" $(YELLOW) $(RESET)
What should I add in order to be able to launch my program and have it find my shared library?
tldr:
$ LD_LIBRARY_PATH="$LD_LIBRARY_PATH:./lib" ./zappy_ai
Longer explanation:
You've dynamically linked
zappy_ai
against
./lib/liblua.so
by using
LDFLAGS = -L./lib/
and
LDLIBS = -llua
The resulting zappy_ai executable requires that same ./lib/ to be present within the LD_LIBRARY_PATH environment variable when the dynamic linker/loader attempts to resolve the -llua symbols that zappy_ai uses.

Makefiles in multiple directories

I want to build an app and I have multiple modules stored in multiple directories. I've decided to follow this idea, i.e. to have a makefile in each directory and then to merge it. But - as a beginner programmer - I still do not see how to do that. First of all, how would such "partial" makefiles look like. They cannot have main function as there can be only one per binary, though when I try to compile it gcc complains for the undefined reference to main. Secondly, I have no idea how would putting all those modules together look like.
I would appreciate any help, but please try to keep your answers simple. Makefiles are still a bit of black magic to me.
Before you can do anything with a makefile, you must know how to do it without a makefile.
Since you are using gcc, I will assume that your source code is C++.
You haven't told us what your directory structure looks like, so I'll suppose that you have three source files in two directories: primary/main.cc, other/foo.cc and other/bar.cc. (We can deal with header files like foo.h later.) And you want to build myApp.
STEP 1: Doing It By Hand
To do this in one command, you might use:
gcc -Wall primary/main.cc other/foo.cc other/bar.cc -o myApp
This will compile the three source files and link the binary objects together into the executable myApp.
STEP 2: Doing It In Pieces (Do not attempt this until you can get the previous step to work perfectly.)
Instead of building with one command, you could take an intermediate step, compiling the source files into binary object files:
gcc -Wall -c primary/main.cc -o primary/main.o
gcc -Wall -c other/foo.cc -o other/foo.o
gcc -Wall -c other/bar.cc -o other/bar.o
This will produce alpha/main.o, beta/foo.o and beta/bar.o. The compiler won't complain about foo and bar lacking a main() function, because an object file doesn't need one. Then link the objects together into an executable:
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 3: Doing It Locally (Do not attempt this until you can get the previous step to work perfectly.)
Just like the previous step, but we act in primary/ and other/:
cd primary
gcc -Wall -c main.cc -o main.o
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 4: Using a Makefile (Do not attempt this until you can get the previous step to work perfectly.)
We could have a makefile perform STEP 1, but that isn't really necessary. Write a makefile in primary (i.e. primary/makefile) like this:
main.o:
gcc -Wall -c main.cc -o main.o
(That whitespace in fromt of gcc... is a TAB.)
Now try this:
cd primary
make
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 5: Using Several Makefiles (Do not attempt this until you can get the previous step to work perfectly.)
Write a other/makefile:
both: foo.o bar.o
foo.o:
gcc -Wall -c foo.cc -o foo.o
bar.o:
gcc -Wall -c bar.cc -o bar.o
and a makefile in the top directory, where you're building myApp:
myApp:
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
Now try this:
cd primary
make
cd ../other
make
cd ..
make
STEP 6: Using One Makefile That Calls Others (Do not attempt this until you can get the previous step to work perfectly.)
Edit the top makefile:
myApp:
cd primary; make
cd other; make
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
Now try:
make
If all of this works, what you have is a crude but effective makefile system. There are many refinements possible, when you're ready to take the training wheels off.
EDIT:
If there are many source files in a subdirectory (e.g. other/) and you don't want to maintain a list in the top makefile by hand, there are several ways to handle it. This is one:
OTHER_SOURCES := $(wildcard other/*.cc)
OTHER_OBJECTS := $(OTHER_SOURCES:.cc=.o)
myApp:
cd primary; make
cd other; make
gcc -Wall primary/main.o $(OTHER_OBJECTS) -o myApp
But you should get these makefiles working and understand them, before you try any more streamlining.

Resources