How do I apply a flag to a library in SCons? - build

I need to execute a build command similar to:
g++ -Wl,-rpath=../libs source.o -static -Wl,-Bdynamic -ldynlib -Wl,-Bstatic -lstaticlib
My current (wrong) SConscript links in dynlib with this line:
env.AppendUnique(LINKFLAGS=['-Wl,-Bdynamic', '-ldynlib']);
However when I run scons, I get this:
g++ -Wl,-rpath=../libs -static -Wl,-Bdynamic -ldynlib source.o -Wl,-Bstatic -lstaticlib
Because source.o is after dynlib, it can't find dynlib, and this causes link errors. The solution (verified manually) is to move source.o before dynlib, which is a vendor-provided library.
Ideally I'd add dynlib to LIBS but SCons does not appear to support flags there.
What workaround can I use to get SCons to generate the correct build line?

Literal turned out to be the solution. For whatever reason, SCons doesn't prepend '-l' to my flags now.
env['FORCEDYNAMIC'] = env.Literal('-Wl,-Bdynamic')
env.PrependUnique(LIBS = [['${FORCEDYNAMIC}', 'dynlib']])

Related

Understanding LD under MSYS2

I'm trying to compile the simavr project from https://github.com/buserror/simavr on Windows 10 using MSYS2 and mingw-w64.
After editing the makefiles to enable the MSYS clauses (Which are commented out by default), and changing the order of 2 include files, I can get the project to compile. I do however encounter an error in the linking step.
The output is
C:/Programs/msys64/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lsimavr
Editing the makefile to print the ${LDFLAGS}, yield the following.
-L/lib -L/local/lib -L/c/Users/University/GitHub/simavr/simavr/../simavr/obj-i686-w64-mingw32 -lsimavr -lelf -lws2_32
Looking in the folder "obj-i686-w64-mingw32" mentioned in the build script, the file "libsimavr.a" is present. If I copy the file to the msys lib folder the linking step works fine.
The folder structure of the project is as follows:
simavr root (Where i run the makefile from, located in /c/Users/University/GitHub)
simavr
obj-i686-w64-mingw32
As far as I can tell, LD should be able to link properly without me copying the file manually. What am I missing here?
Edit:
The final command before the linker error.
cc -MMD -Werror -O2 -Wall -g -I/usr/local/include -DNO_COLOR -o obj-i686-w64-mingw32/run_avr.elf obj-i686-w64-mingw32/run_avr.o -L/lib -L/local/lib -L/c/Users/University/GitHub/simavr/simavr/../simavr/obj-i686-w64-mingw32 -lsimavr -lelf -lws2_32
Edit 2:
Cleaning the include paths of MSYS folders:
cc -MMD -Werror -O2 -Wall -g -DNO_COLOR -o obj-i686-w64-mingw32/run_avr.elf obj-i686-w64-mingw32/run_avr.o -L/c/Users/University/GitHub/simavr/simavr/../simavr/obj-i686-w64-mingw32 -lsimavr -lelf -lws2_32
C:/Programs/msys64/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lsimavr
Passing CC=gcc to make:
gcc -MMD -Werror -O2 -Wall -g -DNO_COLOR -o obj-i686-w64-mingw32/run_avr.elf obj-i686-w64-mingw32/run_avr.o -L/c/Users/University/GitHub/simavr/simavr/../simavr/obj-i686-w64-mingw32 -lsimavr -lelf -lws2_32
C:/Programs/msys64/mingw32/bin/../lib/gcc/i686-w64-mingw32/5.3.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lsimavr
Edit 3:
Output of the find command:
$ find /c/Users/University/GitHub/simavr -name 'libsimavr.a'
/c/Users/University/GitHub/simavr/simavr/obj-i686-w64-mingw32/libsimavr.a
Note that previous entries have been made using the git bash prompt, not the one from msys2. However, running the same commands in the msys2 prompt or the mingw prompt from msys2 yields the same results.
Using mingw-w64 toolchain to build project you MUST remove from CFLAGS/CXXFLAGS/CPPFLAGS all paths with /usr, /local, /lib, /include as this paths can contain headers and libs from MSYS2 itself. Second, try pass "CC=gcc" to makefile.

c++ shared library in custom directory is not found

I want to use a shared library (resides in a custom directory) into an executable.
I've created this makefile
all: SayHello
SayHello: compiledObjects/SayHello.o myLib/libNames.so
g++ compiledObjects/SayHello.o -o SayHello -Icommons -LmyLib -lNames
compiledObjects/SayHello.o: SayHello.cpp
g++ -c SayHello.cpp -o compiledObjects/SayHello.o
myLib/libNames.so: commons/Names.cpp commons/Names.h
g++ -shared -fPIC commons/Names.cpp -o myLib/libNames.so
That create correctly the executable and shared library infact I can Execute the program using this command
LD_LIBRARY_PATH=/custom/path/to/lib/myLib/libNames.so
./SayHello
How can I execute ./SayHello without specify LD_LIBRARY_PATH?
I'm not using any IDE and I'm on linux.
Use the -rpath option to link your executable. See the ld(1) manual page for more information.
P.S. Your makefile appears to have a bug. If you successfully make your program, and immediately run make again, looks like your makefile will attempt to recompile the program again, even though nothing has changed.
After all, the whole purpose of a makefile is to avoid doing unneeded compilations.
The SayHello.o build target should be compiledObjects/SayHello.o.
You need to tell g++ to pass the -rpath option to the linker using -Wl,-rpath. Also, you need to specify a path to the -rpath option.
Putting it all together your last build step should look like this:
SayHello: compiledObjects/SayHello.o myLib/libNames.so
g++ compiledObjects/SayHello.o -o SayHello -Icommons -LmyLib -lNames -Wl,-rpath=/custom/path/to/lib/myLib/
Relative RPATH:
If you want to specify an RPATH relative to your binary you should use
$ORIGIN as a placeholder: -rpath='$ORIGIN/rel/path'.

mingw g++ is unable to link with libraries

I'm trying to use X86_64-w64-mingw32-g++ (packaged in Archlinux's MingW package) to cross compile some C++ code into an Windows executable, however I'm having trouble getting past some issues.
I'm calling
x86_64-w64-mingw32-g++ -o build_win/asm build_win/asm.o build_win/asm_lib.o build_win/socket_boost.o -I../extra/etc -fopenmp -lrt -std=c++11 -g -lboost_system -lboost_serialization
from a makefile, but I get thrown the errors:
/usr/lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld: cannot find -lrt
/usr/lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld: cannot find -lboost_system
/usr/lib/gcc/x86_64-w64-mingw32/5.1.0/../../../../x86_64-w64-mingw32/bin/ld: cannot find -lboost_serialization
This works fine with native g++, so exactly do I have to change for mingw to compile?
EDIT: I have mingw-w64-boost package installed, which includes boost libraries pre-compiled and ready to be linked. However, it seems the naming convention is a bit different, and -lboost_system for example becomes -llibboost_system-mt (not exactly sure what the -mt suffix entails).
Problem is I can't find the mingw counterpart for -lrt. I've tried with both -lrtm and -lrtutils but in both cases I get:
[...]
undefined reference to `__imp_getsockopt'
Are you sure that -lboost_system and other libraries are present in the same directory as makefile ?
If not then please include -L flag which indicates the location of your library.
For example:
-L /path_openmp -fopenmp -L /path_boost_system/ -lboost_system -L /path_serialization -lboost_serialization
Moreover, you need not include -I and -g flag when creating an executable from .o files. These are needed when you create .o from .cpp files.
There is no rt library on Windows.
You are missing -lws2_32.
$ x86_64-w64-mingw32-nm -A /usr/x86_64-w64-mingw32/lib/*.a 2>/dev/null | grep getsockopt | grep " T "

Bad compilation command from autoconf test

I'm trying to write an autoconf test for a C++ library. I followed http://nerdland.net/2009/07/detecting-c-libraries-with-autotools/ . My check looks like this:
SAVED_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -lMyLib"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <mylibheader.hpp>],
[MyLibNamespace::SomeObject obj()])],
[TEST_LIBS="$TEST_LIBS -lMyLib"] [HAVE_MYLIB=1],
[AC_MSG_ERROR([libMyLib is not installed.])])
LDFLAGS=$SAVED_LDFLAGS
The test fails. If i check config.log the problem seems to be with the generated compilation command given by autoconf for the check:
g++ -o conftest -g -O2 -lMyLib conftest.cpp
As you can see, the -l params aren't at the end, after all inputs and outpus. If i copy&paste the conftest.cpp code from config.log i can make it compile with:
g++ -o conftest -g -O2 conftest.cpp -lMyLib
How can autoconf be wrong? How may i fix this?
The problem is that you're adding -lMyLib to LDFLAGS instead of adding to LIBS. In other words, do this instead:
SAVED_LIBS=$LIBS
LIBS="-lMyLib $LIBS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <mylibheader.hpp>],
[MyLibNamespace::SomeObject obj()])],
[TEST_LIBS="$TEST_LIBS -lMyLib"] [HAVE_MYLIB=1],
[AC_MSG_ERROR([libMyLib is not installed.])])
LIBS=$SAVED_LIBS
Edit: link order of libraries is important, so I've updated the LIBS= line to link MyLib before the other libraries, if any, with the assumption that MyLib may depend on other libraries.

Static linking with Boost and ncurses

I am in the process of making a basic role-playing game. I want to include the Boost libraries statically so that the people who run my game do not need to have them. I researched and looked-up that all you have to do is add -static to the command-line compile, so my command is like this:
$ g++ -static -o karthas *.o -lncurses -lmenu -lboost_system -lboost_filesystem
But apparently the -static is affecting ncurses. I am getting a whole bunch of errors, most of which are undefined reference to 'SP'.
Is it possible to just do a static link to Boost and not ncurses? How would I go about doing that?
You can choose which libraries will be linked statically and which will be linked dynamically by putting either -Wl,-static or -Wl,-Bdynamic before their name.
For example, with:
g++ -o karthas *.o -Wl,-static -lmenu -lboost_system -lboost_filesystem -Wl,-Bdynamic -lncurses
The menu, boost_system and boost_filesystem libraries will be linked statically and ncurses dynamically.
(But you can also distribute the boost dlls with your executable, and not link anything statically).
But looking at this, it seems that you are not alone, either that, or I found your issue. But this, might have your solution, either way, good luck.
Btw, some boost libraries are little more than inline functions that are imported when included in the file.