I wrote a little Lua module in C, that generates a UUID leveraging libuuid. You can find the source at https://github.com/Mashape/lua-uuid
The library properly works on OSX and CentOS. I am currently having a problem on Ubuntu where although the library successfully compiles, executing it throws the following exception:
lua: error loading module 'lua_uuid' from file './lua_uuid.so':
./lua_uuid.so: undefined symbol: uuid_generate
stack traceback:
[C]: ?
[C]: in function 'require'
/test.lua:1: in main chunk
[C]: ?
It seems like the library can't find the libuuid dependency, although in the Makefile includes the -luuid flag (https://github.com/Mashape/lua-uuid/blob/master/Makefile#L4).
To replicate the problem, these are the dependencies required:
apt-get install lua5.1 luarocks unzip git make gcc uuid-dev
wget https://github.com/Mashape/lua-uuid/archive/0.1-7.zip -O /tmp/lua_uuid.zip
unzip /tmp/lua_uuid.zip -d /tmp
cd /tmp/lua-uuid-0.1-7/ && luarocks make lua_uuid-0.1-7.rockspec
Then you can run the following Lua script:
local uuid = require "lua_uuid"
local uuid_str = uuid()
print("New UUID: "..uuid_str)
I am not proficient with C and Makefiles, is there something obvious that I am missing?
Compiling this module using LuaRocks on Ubuntu results in the following compiler command lines:
gcc -c -O2 -fPIC -I/usr/include/lua5.1 lua_uuid.c -o lua_uuid.o
gcc -shared -luuid -o lua_uuid.so -L/usr/lib lua_uuid.o
The library libuuid is available as a static library, and it is listed before the object file that references its symbols. Since the GNU linker inspects libraries/object files from left to right, all symbolds in libuuid are deemed unnecessary and left out of the final build because they haven't been referenced yet. Moving -luuid to the end of the linker command line (to the right of lua_uuid.o) fixes the issue.
There are already some Stackoverflow answers that explain the particulars:
Why does the order in which libraries are linked sometimes cause errors in GCC?
Why does the order of '-l' option in gcc matter?
Related
Currently I am building a foo.h and foo.c with:
$ clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o foo.dylib foo.c
I am able to use this in other C libraries like this:
clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o bar.dylib bar.c foo.dylib
I would like to use this library in an assembly project.
$ nasm -f macho64 test.asm \
&& ld -e start -macosx_version_min 10.13.0 -static -o test test.o foo.dylib
$ ./test
ld: warning: foo.dylib, ignoring unexpected dylib file
Wondering how I link together the C -> asm system to get the C functions working in asm. Then I would like to go further and use that compiled asm to use in either a C or asm project, so wondering how to do that.
When using the assembly in C, I would like for you to basically get functions and import #include "myassembly.h" or something like that, so it feels like a real library. Then you have a function like myfunc which is defined in assembly, but you can use it in c as myfunc(1, 2, 3); sort of thing.
If I change it from static to dynamic linking with the -lSystem flag (and removing -static), I get this:
dyld: Library not loaded: foo.dylib
Referenced from: ./test
Reason: image not found
make: *** [...] Abort trap: 6
You're specifying -static which means:
-static Produces a mach-o file that does not use the dyld. Only used
building the kernel.
dyld is the dynamic loader. If you're not using the dynamic loader, you can't use dynamic libraries.
Update for edited question:
When a dylib is created, it gets an "install name". When an executable is linked to that dylib, the executable stores the install name of the dylib in its reference to it. (Note, it does not store the link-time path of the dylib file it linked against.) When the executable is loaded, the dynamic loader looks for the dylib using the install name it recorded, by default.
You can specify the install name using the -install_name <name> option to the linker. It could be the absolute path to where you expect the library to be installed (e.g. /usr/local/lib/foo.dylib), if you expect it to be installed in a fixed location. Often, though, that's not useful. You want a more flexible means for the dynamic loader to find the dylib.
The dynamic loader understands certain special path prefixes on install names to support such flexibility. See the dyld(1) man page. For example, if you specify an install name of #executable_path/foo.dylib then, at load time, the loader will look next to the executable for the library.
You can see the install name of a dylib by using otool -D foo.dylib. Your dylib may not have an install name, in which case its effective install name is just its file name with no path.
If the loader doesn't find the library by using its install name, it has a search strategy. By default, it looks in ~/lib:/usr/local/lib:/lib:/usr/lib. You can use some environment variables to alter the search strategy. For example, you can set DYLD_FALLBACK_LIBRARY_PATH to a colon-delimited list of directories to search, instead. These environment variables are also listed in the dyld(1) man page.
Based on This Stackoverflow link I downloaded & installed glibc v2.29 in "/usr/local/glibc" path of Linux OS. Then based on this Stackoverflow link I tried to compile This Example, But I got following errors.
First Try Command:
gcc -Wall -g -o main main.c -Wl,--rpath=/usr/local/glibc/lib -Wl,--dynamic-linker=/usr/local/glibc/lib/ld-linux-x86-64.so.2
First Try Error Log:
main.c:1:10: fatal error: threads.h: No such file or directory
#include <threads.h>
^~~~~~~~~~~
compilation terminated.
Second Try Command:
In second try, I am using "-I" & "-L" GCC command options.
gcc -Wall -g -I/usr/local/glibc/include -o main main.c -L/usr/local/glibc/lib -Wl,--rpath=/usr/local/glibc/lib -Wl,--dynamic-linker=/usr/local/glibc/lib/ld-linux-x86-64.so.2
Second Try Error Log:
/tmp/ccCNYemW.o: In function `main':
/home/.../main.c:14: undefined reference to `thrd_create'
/home/.../main.c:16: undefined reference to `thrd_join'
collect2: error: ld returned 1 exit status
So I don't know where is the problem. Please Help me.
First of all, don't put an alternate libc (or alternate version of your libc) in a path searched by the normal include and library search (both link-time and runtime library search) for your main system one. This is a recipe for disaster. Installing a different glibc in /usr/local/ does avoid clobbering your system one, but now you just have two installed in places where the same tools can see and use them.
To do this right, you really need a full separate toolchain (gcc, binutils) in some completely separate path (like ~/my_glibc_root/... or /opt/alt_glibc_root/...). I'm not sure if there's a recommended way to do this. The glibc build procedures in Linux From Scratch might be a good place to look for ideas. In theory it can be done in a single stage; I do that with musl libc in musl-cross-make by careful use of intermediate make rules in the gcc build system. But applying the same idea to glibc probably requires some extra care.
Second Try Command: In second try, I am using "-I" & "-L" GCC command options.
gcc -Wall -g -I/usr/local/glibc/include -o main main.c -L/usr/local/glibc/lib -Wl,--rpath=/usr/local/glibc/lib -Wl,--dynamic-linker=/usr/local/glibc/lib/ld-linux-x86-64.so.2
This command is almost correct. The thrd_create and thrd_join functions are defined in libpthread, which you didn't link against.
Add -pthread to your compile command, and the link should succeed.
P.S. R's advice of not installing alternate GLIBC into /usr/local is also a good one.
I'm using cmake to generate a gstreamer library. In the end cmake uses the following command for linking:
/usr/bin/cc -fPIC -shared -Wl,-soname,libmacq-gstmelpi.so -o libmacq-gstmelpi.so <OBJECT_FILES> -lmacq-melpi -lmacq-icar-tools -lmacq-gstmecimeta -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lgstvideo-1.0
Note the -lgstvideo-1.0 flag at the end. The command runs fine, no error is produced, and the resulting library is created just fine. However when I use the library, I get undefined symbol error. So I use ldd to check; and amongst all the output of ldd; libgstvideo-1.0.so is not to be found.
This problem occurs on Ubuntu 14.04 on a armhf architecture. The problem does not occur on opensuse 13.1 (i586) nor on opensuse 13.1 (armv7hl), since in that case ldd libmacq-gstmelpi.so | grep gstvideo gives:
libgstvideo-1.0.so.0 => /usr/lib/libgstvideo-1.0.so.0 (0xb715f000)
EDIT :
I have another library, very similar where a very similar command works just fine; the resulting library is correctly linked to libgstvideo-1.0.so
/usr/bin/cc -fPIC -shared -Wl,-soname,libmacq-gstplugins.so -o libmacq-gstplugins.so <OBJECT_FILES> -lmacq-icar-tools -lmacq-gstmecimeta -lgstapp-1.0 -lgstbase-1.0 -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0 -lgstvideo-1.0
Some remarks on what I have checked and tried:
/usr/lib/arm-linux-gnueabihf/libgstvideo-1.0.so exists. (the other libraries in /usr/lib/arm-linux-gnueabihf/ are found without problem, libmacq-gstmelpi.so is linked to /usr/lib/arm-linux-gnueabihf/libgstreamer-1.0.so.0 without problem)
I tried changing the order, and putting the -lgstvideo-1.0 flag before all other -l flags; no succes.
replacing cc with c++ or gcc; the commands work, but output is the same
removing -lgstvideo-1.0 on a system where the build worked. The resulting library builds (links) without error; yet upon execution I have the same undefined symbol error as on Ubuntu. This proves that the missing symbol is in libgstvideo-1.0.so, and that I need it.
Are you actually using symbols from that particular library or do you just want to link to it to avoid linking it in the application that uses the library later on?
It could be a default compiler behavior that it skips linking of libraries when no symbol from these are actually used.
Try -Wl,--no-as-needed to your flags. In this case the library should get linked - not checking whether its symbols are actually used or not.
EDIT:
After chatting it turned out that the actual desired symbols are in gstbase-1.0 and not gstvideo-1.0. Since gstvideo-1.0 pulls in gstbase-1.0 as a dependency this worked but would cause problem as the linker may remove this dependency since no symbols from this particular library are being used. Linking directly to gstbase-1.0 seemed to solve all issues.
I'm trying to use Scons to build a simple project on a server on which I have rights to install stuff only in specific locations (and not in /usr/ ). Since I'm not happy with default compiler the server is offering me, I installed g++4.8 and verified it works just fine. But when I try to use Scons to build a simple project, while it picks up correct g++ (I can get that by checking the version), it's looking for libstdc++ in /usr/ directories instead of the directory where g++4.8 installation resides. E.g. code compiles, but upon execution fails with:
./main: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./main)
Again - this doesn't happen when I call the compiler myself from the terminal.
Even when I add the lib path containing libraries for g++4.8 with LIBPATH option, I get the same error.
Here's my SConscript file:
Import('env')
COMPILER_FLAGS = '-Wall -fopenmp -O3 -std=c++11'
LINK_FLAGS = '-Wall -fopenmp -O3 -std=c++11'
LIB_PATH = 'myfolder/gcc-4.8.2/lib64'
PROGRAM = 'main'
SRC = ['main.cpp', 'Foo.cpp']
env.Append(CPPFLAGS = COMPILER_FLAGS)
env.Append(LINKFLAGS = LINK_FLAGS)
env.Program(target = PROGRAM, source = SRC, LIBPATH = LIB_PATH)
and SConstruct is just
import os
env = Environment(ENV = os.environ)
SConscript('./SConscript', exports=['env'], duplicate=0)
Edit:
I made sure location of my compiler comes in the path before default compiler. But even if I set it explicitly with Environment(CXX=...) it's the same story. Here's the build output:
/mypath/gcc-4.8.2/bin/g++ -o Foo.o -c -Wall -fopenmp -O3 -std=c++11 Foo.cpp
/mypath/gcc-4.8.2/bin/g++ -o main.o -c -Wall -fopenmp -O3 -std=c++11 main.cpp
/mypath/gcc-4.8.2/bin/g++ -o main -Wall -fopenmp -O3 -std=c++11 main.o Foo.o -L/mypath/gcc-4.8.2/lib64
scons: done building targets.
-bash-3.2$
-bash-3.2$
-bash-3.2$ ./main
./main: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./main)
./main: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by ./main)
-bash-3.2$
Yet another edit:
ldd on both manual and scons compile reveal:
linux-vdso.so.1 => (0x00007fff513fd000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6(0x0000003e7f600000)
libm.so.6 => /lib64/libm.so.6 (0x0000003e79600000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003e7de00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003e79200000)
/lib64/ld-linux-x86-64.so.2 (0x0000003e78e00000)
So indeed even manual compile doesn't look for the libs in the right directory (or where I installed the compiler) and the problem isn't with the scons itself, but likely that I didn't configure something right, but then I'm really puzzled as to why the executable runs fine, while it doesn't for scons.
Ok, so my problem wasn't with scons, but with me not giving explicit paths to nonstandard locations of libstdc++ and friends. SO answer over here explains this in more detail:
Linking g++ 4.8 to libstdc++
You're misinterpreting the error. GCC always knows how to find its own libraries, including libstdc++. The problem is that after you've compiled the program the runtime linker (which is not part of GCC, it's part of your OS and comes from glibc) doesn't know how to find the newer libstdc++, so it finds the default system one, which is too old.
The problem and solution are described at in the Libstdc++ FAQ, "How do I insure that the dynamically linked library will be found?", and manual, "Finding Dynamic or Shared Libraries"
This doesn't sound right.
Can you show us what you do to override the compiler?
If you are only doing the above, I don't think your compiler will be overridden with the new version.
You need to do something like
env = Environment(CC='/path/to/gcc')
Or Environment(CXX='/path/to/g++') if you want to override the c++ compiler
Or is your path on your environment setup to have the directory of the custom compiler before the standard compilers directory?
It might help to clean and then run with scons with --debug=presub which will show you the command line used to build each target.
Also your environment is a dictionary, so try printing out different keys to make sure they match what you expect:
print env['CC']
print env['CXX']
I started experimenting with C/C++ the other day because I needed it for reading level-4 MAT-files without needing to purchase the Matlab editor or compiler. So I found just the library that I needed but I'm not familiar with C or C++ at all so I'm a beginner with those two languages. Anyhow I need to include the 'matio' library. I've tried many things but I've had no luck.
I right clicked on the C/C++ project > properties > C/C++ General > Paths & Symbols > GNU C and added the path to the matio library.
I also went to C/C++ Build > Settings > Tool settings > GCC C Compiler > Includes and added the path there aswell.
Since I'm not any good with makefiles yet I did not specify my own makefile, instead I chose a executable project.
When I try to build my project it complains about a function called 'Mat_Open' in the matio library. When I hover over it, it says "undefined reference to 'Mat_Open'" the header 'matio.h' seems to work fine but it can't refer to 'Mat_Open' for some reason.
How do I solve this?
EDIT:
Here is the whole build console output.
10:42:52 **** Incremental Build of configuration Debug for project Project ****
Info: Internal Builder is used for build
gcc -IC:/matio-1.5.2/src -O0 -g3 -Wall -c -fmessage-length=0 -o CComponent.o "..\\CComponent.c"
gcc -Xlinker -lm -o Project.exe CComponent.o -lC:/matio-1.5.2/src
c:/mingw(x64)/bin/../lib/gcc/x86_64-w64-mingw32/4.8.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lC:/matio-1.5.2/src
collect2.exe: error: ld returned 1 exit status
10:42:53 Build Finished (took 330ms)
This is not necessarily an answer but may be useful for a comparison.
First of all, where did you install it? If your using Linux or Mac OSX you will want to install in the system directories (not sure about Windows). I use OSX so in my makefile (by the way I use Qt):
LIBS += -L/usr/local/lib/ -lmatio
INCLUDEPATH += /usr/local/include
Then of course, in the *.h files of my source I use:
#include "matio.h"
But I assume you have already tried that?