I'm porting a small program to run on my RPi from my windows machine. The code is correctly ported but I'm having some issues with the linking process. Googling or searching on here has yielded nothing that worked. My .so files are correctly lying in the /mnt/client/dbg/ directory on external storage, can that be an issue?
g++ -shared -o dbg/socketwrappers.so socketwrappers.o
g++ -shared -o dbg/mylibrary2.so mylibrary2.o
g++ -shared -o dbg/mylibrary3.so mylibrary3.o
g++ -L/mnt/client/dbg/ -o dbg/client client.cpp -lsocketwrappers -lmylibrary2 -lmylibrary3
/usr/bin/ld: cannot find -lsocketwrappers
/usr/bin/ld: cannot find -lmylibrary2
/usr/bin/ld: cannot find -lmylibrary3
Filetree from pwd (/mnt/client):
├── ./dbg
│ ├── /socketwrappers.so
│ ├── /mylibrary2.so
│ └── /mylibrary3.so
├── ./makefile
└── ./client.cpp
Related
This is the command I'm trying to run
g++ mario_game/main.cpp mario_game/game.cpp mario_game/mario.cpp dream.cpp -lSDL2 -lSDL2_ttf -lSDL2_mixer -lSDL2_image -std=c++11 -I DreamEngine/DreamEngine2/include -o mario
Here's the directory structure
DreamEngine
└── DreamEngine2
├── 8bit.ttf
├── a.out
├── dream.cpp
├── hello.cpp
├── include
│ └── dream.h
├── LICENSE
└── mario_game
├── game.cpp
├── game.h
├── globalvars.h
├── main.cpp
├── mario.cpp
└── mario.h
Any help will be appreciated. :)
I tried the comment that is said above and it says include not found.
I wanted to learn how to make a shared library in C++. So I found some logic to generate Mandelbrot PPM images, and encapsulated it in src/mandelbrot.cpp (with accompanying header file include/mandelbrot.cpp). Directory tree looks like:
$ tree
.
├── Makefile
├── include
│ └── mandelbrot.h
├── lib
│ └── mandelbrot.dylib
└── src
├── client.cpp
├── main
├── main.cpp
├── mandelbrot.cpp
└── mandelbrot.o
The goal is for src/client.cpp to use lib/mandelbrot.dylib to draw the fractal without having access to src/mandelbrot.cpp or src/mandelbrot.o.
Makefile:
.PHONY=clean
main: src/mandelbrot.o
clang++ src/main.cpp -o src/main src/mandelbrot.o -I ./include
src/mandelbrot.o:
clang++ -c src/mandelbrot.cpp -o src/mandelbrot.o -I ./include
clean:
rm src/*.o
rm lib/*.dylib
lib/mandelbrot.dylib:
clang++ -dynamiclib -o lib/mandelbrot.dylib src/mandelbrot.cpp -I ./include
src/client: lib/mandelbrot.dylib
clang++ src/client.cpp -o src/client -L ./lib -I ./include
Running the executable without the dylib works:
$ make main
clang++ src/main.cpp -o src/main src/mandelbrot.o -I ./include
$ ./src/main # runs fine!
But I can't get my shared library to link when compiling src/client.cpp:
$ make src/client
clang++ src/client.cpp -o src/client -L ./lib -I ./include
Undefined symbols for architecture x86_64:
"fractal::Mandelbrot::writeToFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)", referenced from:
_main in client-e344c7.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [src/client] Error 1
Even though the symbol seems to be in the dylib:
$ file lib/mandelbrot.dylib
lib/mandelbrot.dylib: Mach-O 64-bit dynamically linked shared library x86_64
$ nm -C lib/mandelbrot.dylib | grep writeToFile
0000000000001460 T fractal::Mandelbrot::writeToFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
I'm trying to dig in deeper and understand the linking/compilation process. How do I make the setup I have work to demonstrate what I want to do?
Try naming your library like libmandelbrot.dylib to match the -lmandelbrot flag
Credit goes to #Daniel for finding the answer, but a bit about why.
I can make the compilation work by renaming mandelbrot.dylib -> libmandelbrot.dylib as suggested by #daniel's answer.
I dug into man ld (the linker) and found the following definition:
-lx This option tells the linker to search for libx.dylib or libx.a in the library search path. If string x is of the form y.o, then that file is searched for in the same places, but without prepending
`lib' or appending `.a' or `.dylib' to the filename.
Thus, if you want to arbitrarily name your dynamically loaded libraries (and for some reason don't like the magic of prepending libxxxx to the name, you'd have to do this (I have confirmed this works):
lib/whatever.o:
clang++ -dynamiclib -o lib/whatever.o src/mandelbrot.cpp -I ./include
src/client: lib/whatever.o
clang++ src/client.cpp -o src/client -L ./lib -I ./include -l whatever.o
TL;DR = By having the -l option as a filename ending in .o, the linker looks directly in the directory specified by -L for the exact filename specified in -l. Otherwise -l foo -L /path/ searches for /path/libfoo.[dylib|a]
I have the following files:
.
├── combinatorics
│ ├── permutation.cpp
│ └── permutation.h
├── main.cpp
└── math
├── basic.cpp
└── basic.h
and am trying to create a shared library by doing these steps:
g++ -c -Wall -std=c++14 -fpic combinatorics/permutation.cpp -o permutations.o
g++ -c -Wall -std=c++14 -fpic math/basic.cpp -o mathbasic.o
g++ -shared -o combmath.so permutations.o mathbasic.o
g++ -Wall -std=c++14 main.cpp -L. -o output -lcombmath
but I am getting the following message:
/usr/bin/ld: cannot find -lcombmath
collect2: error: ld returned 1 exit status
what am I doing wrong?
The linkage option -lfoo directs the linker to search for a file
libfoo.so (shared library) or libfoo.a (static library) in the specified
linker search directories (-L/x/y/z) and then in the linker's default
search directories, stopping when it finds either one of those files and
preferring libfoo.so if it finds both in the same directory.
For your linkage:
g++ -Wall -std=c++14 main.cpp -L. -o output -lcombmath
to succeed, therefore, you need previously to have built libcombmath.so
in the same directory with the command:
g++ -shared -o libcombmath.so permutations.o mathbasic.o
and not built combmath.so, as you have done with the command:
g++ -shared -o combmath.so permutations.o mathbasic.o
Given I have a project with a straightforward Makefile like so:
all: foobar
foobar: foo.o bar.o
that I can build to target different architectures:
$ CC=clang make # or
$ CC=x86_64-w64-mingw32-gcc make # or
$ CC=arm-linux-gnueabihf-gcc make
This works but I want to be able to maintain outputs for multiple configurations at the same time, for example on a build server.
What would be a good, clean way to go about this? I've considered the following:
Use autotools or another build tool, but I want to see what's possible without
Create build directories with Makefiles in them that set VPATH and include the root Makefile
Write a script that moves the output after building each architecture
Modify the Makefile to build multiple configurations. I don't like this solution because you end up with a sort of meta-Makefile that's complex and tightly coupled to your specific build environment
Add a variable to the Makefile to set the output directory. This could work but it means I can't use implicit Makefile rules. Pattern rules would get messy too
I would go with something like that:
# User configuration
BINARY := hello
SOURCES := main.c
# Create the output paths
out ?= out
outdir := $(out)/$(CC)
outbin := $(outdir)/$(BINARY)
objects := $(outdir)/$(SOURCES:.c=.o)
# Default target
all: $(outbin)
# Binary target
$(outbin): $(objects)
$(CC) -o $# $^
# Objects target
$(objects): $(outdir)/%.o: %.c
mkdir -p $(#D)
$(CC) -o $# -c $<
# The cleanning targets
clean:
$(RM) -r $(outdir)
mrproper:
$(RM) -r $(out)
# Declare phony targets
.PHONY: all clean mrproper
Note that the objects target is using static pattern to be able to get the source files in the current directory and the object files in the output directory.
It is also as easy to use as a basic Makefile:
$ make
mkdir -p out/cc
cc -o out/cc/main.o -c main.c
cc -o out/cc/hello out/cc/main.o
$ make
make: Nothing to be done for 'all'.
$ tree
.
├── main.c
├── Makefile
└── out
└── cc
├── hello
└── main.o
2 directories, 4 files
$ CC=gcc make
mkdir -p out/gcc
gcc -o out/gcc/main.o -c main.c
gcc -o out/gcc/hello out/gcc/main.o
$ tree
.
├── main.c
├── Makefile
└── out
├── cc
│ ├── hello
│ └── main.o
└── gcc
├── hello
└── main.o
3 directories, 6 files
I have 2 directories in my project, one called Builds, who has the Makefile and a test program ( test-P0-consola.cpp ) and other one directory called P0 who constains the classes I use, cadena (string) and fecha (date).
test-P0-consola.cpp includes both of them, but Make doesn't find them.
CPP = g++
CPPFLAGS = -std=c++14 -g -Wall -pedantic
VPATH = ../P0:.:..
test-consola: test-P0-consola.o fecha.o cadena.o
${CPP} ${CPPFLAGS} -o $#.ex $^
test-P0-consola.o: test-P0-consola.cpp fecha.hpp cadena.hpp
${CPP} -c ${CPPFLAGS} $< -o $#
fecha.o: fecha.hpp
cadena.o: cadena.hpp
It throws the fatal error "cadena.hpp doesn't exist the file or directory" when it tries to compile test-P0-consola.o, but It find them out when I force it to compile cadena or fecha. I'm using GCC and Ubuntu.
..
├── Builds
│ ├── makefile.mak
│ └── test-P0-consola.cpp
├── P0
│ ├── cadena.cpp
│ ├── cadena.hpp
│ ├── fecha.cpp
│ └── fecha.hpp
EDIT
Error:
g++ -std=c++14 -g -Wall -pedantic -c test-P0-consola.cpp
test-P0-consola.cpp:7:21: fatal error: fecha.hpp: There is no file or directory
compilation terminated.
makefile.mak:9: Failure in the instructions for the objective 'test-P0-consola.o'
make: *** [test-P0-consola.o] Error 1
Look closely at your error:
test-P0-consola.cpp:7:21: fatal error: fecha.hpp: There is no file or directory
You probably have something like:
// test-P0-consola.cpp
#include "fetcha.hpp"
But fetcha.hpp is not in that directory, so it can't find it. You either need to change the way you include the file directly (via #include "../P0/fetcha.hpp") or to change the build rule to pass in an additional include path (via -I../P0).
Note: I'm not sure there's a reason to add . to VPATH. That's kind of implicit.
Note 2: this is a bad idea:
test-consola: test-P0-consola.o fecha.o cadena.o
${CPP} ${CPPFLAGS} -o $#.ex $^
~~~~~
Don't lie to Make. The result of running a recipe should be the target file, except for PHONY targets. The recipe here should be -o $#. If you want the .ex suffix, you should change the target to be test-consola.ex. If you still want the rule to be named test-consola, you'll want:
test-consola : test-consola.ex
test-consola : .PHONY
You should put in the makefile the include path of the .hpp files you need the compiler to use. You should use the -Ipath compiler directive, where path is the path of your include files.
See `Makefile: How to correctly include header file and its directory?
and
How to define several include path in Makefile
Something like:
CPP = g++
CPPFLAGS = -std=c++14 -g -Wall -pedantic
INC = -Iyourincludebasepath/P0
VPATH = ../P0:.:..
test-consola: test-P0-consola.o fecha.o cadena.o
${CPP} ${CPPFLAGS} ${INC} -o $#.ex $^
test-P0-consola.o: test-P0-consola.cpp fecha.hpp cadena.hpp
${CPP} -c ${CPPFLAGS} ${INC} $< -o $#
fecha.o: fecha.hpp
cadena.o: cadena.hpp