I'm trying to write a C program using a library. The library has provided a include/ and lib/ directory with header files and .dylib files, respectively.
My file is in the same directory as include/ and lib/. I'm trying to compile it with the following command:
clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window test.c
However, when I go to run my program, I get the following error:
% ./a.out
dyld: Library not loaded: #rpath/libcsfml-graphics.2.4.dylib
Referenced from: ~/src/CSFML-2.4-osx-clang/./a.out
Reason: image not found
zsh: abort ./a.out
What is the correct way to compile using these libraries? I'd prefer to simply use the command line as I'm writing a small program, without having to set up Xcode, etc.
% ls -l lib/
-rwxr-xr-x# 1 staff 50296 Mar 1 2017 libcsfml-audio.2.4.0.dylib*
lrwxr-xr-x# 1 staff 26 Mar 1 2017 libcsfml-audio.2.4.dylib# -> libcsfml-audio.2.4.0.dylib
lrwxr-xr-x# 1 staff 24 Mar 1 2017 libcsfml-audio.dylib# -> libcsfml-audio.2.4.dylib
-rwxr-xr-x# 1 staff 163680 Mar 1 2017 libcsfml-graphics.2.4.0.dylib*
lrwxr-xr-x# 1 staff 29 Mar 1 2017 libcsfml-graphics.2.4.dylib# -> libcsfml-graphics.2.4.0.dylib
lrwxr-xr-x# 1 staff 27 Mar 1 2017 libcsfml-graphics.dylib# -> libcsfml-graphics.2.4.dylib
-rwxr-xr-x# 1 staff 67272 Mar 1 2017 libcsfml-network.2.4.0.dylib*
lrwxr-xr-x# 1 staff 28 Mar 1 2017 libcsfml-network.2.4.dylib# -> libcsfml-network.2.4.0.dylib
lrwxr-xr-x# 1 staff 26 Mar 1 2017 libcsfml-network.dylib# -> libcsfml-network.2.4.dylib
It seems that after fixing rpath with clang -I"./include/" -L"./lib/" -lcsfml-graphics -lcsfml-window -Wl,-rpath,"#executable_path/lib" test.c you're still missing SFML libraries. I've just checked that CSFML depends on SFML, and based on your ls -l lib/ listing, SFML is clearly absent in lib/. My guess is that after fixing rpath you may not have noticed that the absent dependency has changed to #rpath/libsfml-graphics.2.4.dylib instead of #rpath/libcsfml-graphics.2.4.dylib. Please, download SFML libraries and put them into lib/.
Now to your question, how to build on macOS from the command line. Your building steps are correct, so I suppose the difficult part is how the dependencies are searched by dyld, not how they're linked with ld.
A short theory.
There are 4 ways a binary (an executable or a dynamic library) references its dependencies:
by an absolute or relative path (the latter is relative to your working directory);
by #executable_path, expanding to the path of the executable which is the root of the dependency tree (in case you have recursive dependencies);
by #loader_path, expanding to the path of the executable or a library for which the dependency is searched, i.e. it's the path of the direct parent in the dependency tree;
by #rpath, which is substituted in turn by each rpath found in your binary, and this is the most flexible way as you can search in several directories by having multiple rpaths.
Now the question is how to ensure the dependencies are correctly referenced. As #mattmilten pointed out, there are 2 methods for that:
make your build system/build script/manual build commands ensure the references are correct;
use install_name_tool to correct the broken references.
Making it automatic during the build.
In order for the first method to work you need to make sure the identification names of the dependency libraries are correct. Suppose you're linking a binary against some library libA.dylib. The identification name of libA.dylib is the default reference which will be used by the linker (ld) when building your binary. You can find it by looking at the first line of otool -L libA.dylib (or alternatively at the LC_ID_DYLIB section of otool -l libA.dylib). In case of libcsfml-graphics.2.4.dylib it's #rpath/libcsfml-graphics.2.4.dylib and it was passed to a.out on linking, that's why you're seeing it in the error message when dyld fails to meet it.
Setting a correct identification name is a responsibility of the libA.dylib authors. It is set according to their expectations as to where libA.dylib could be placed (using #rpath is a good choice) as well as their versioning scheme (in case of CSFML version 2.4.0 could be replaced with 2.4.x without losing binary compatibility). If you're building libA.dylib yourself you can set it with -install_name param (e.g. clang -Wl,-dylib -Wl,-install_name,#executable_path/libA.dylib -o libA.dylib liba.c). If it's a 3rd party library you can change it with install_name_tool -id #rpath/libA.dylib libA.dylib.
Identification name, to the best of my knowledge, is only used during linking and not used when loading a binary, so if you prefer the second method of fixing incorrect references with install_name_tool you can ignore it.
Manual fixing.
Fixing the references with install_name_tool is simple but tedious. You'll probably need a script when there are a lot of incorrect references. All you need is the following set of commands (the binary placeholder should obviously be replaced with an actual binary name):
install_name_tool -change #executable_path/libA.dylib #rpath/libA.dylib binary to change reference #executable_path/libA.dylib -> #rpath/libA.dylib;
install_name_tool -add_rpath #executable_path/lib binary to add #executable_path/lib to rpaths;
install_name_tool -delete_rpath #executable_path/lib binary to remove #executable_path/lib from rpaths;
otool -l binary to check existing rpaths (just look at the LC_RPATH sections).
You should check the environment variable DYLD_LIBRARY_PATH. It should contain the path to libcsfml-graphics.2.4.dylib. Another solution might be to add this path to your PATH variable.
You can inspect the paths of your binary with otool -L and modify them with install_name_tool -change. Ideally, though, you should build your binary to contain the correct rpath to its dependencies using -R when linking/compiling.
Related
The scenario is I try to re-link the program to a directory via /proc where these directories into an elf executable.
First, I create a directory with name test
$ mkdir test
Link to an hello binary
# ln /bin/ping test
# exit
Open a file descriptor to the target binary
$ exec 3< test
You know, this descriptor should now be accessible via /proc
$ ls -l /proc/$$/fd/3
lr-x------ 1 febri febri 64 Jul 17 11:09 /proc/2930/fd/3 -> /home/febri/test
Remove the directory previously created
$ rm -rf test
The /proc link should still exist, but now will be marked deleted.
$ ls -l /proc/$$/fd/3
lr-x------ 1 febri febri 64 Jul 17 11:09 /proc/2930/fd/3 -> /home/febri/test (deleted)
Replace the directory with example payload like :
$ cat hello.c
#include <stdio.h>
int main(int argc, char ** argv) {
printf("hello!\n");
return 0;
}
$ gcc -w -fPIC -shared -o test hello.c
$ ls -l test
-rwxrwxr-x 1 febri febri 6894 Jul 17 11:20 test
$ file test
test: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=361c522d3d9db35ad24de9f3162f80f8a26c9c5b, not stripped
So, I running the linked program and the output is :
$ ./test
Segmentation fault (core dumped)
My question is :
Why the program crash when executed? if anyone can explain?
In fact, the directories and/or symbolic links you messed around with have absolutely nothing to do with the segmentation fault you're facing. Let's look at the command line options you're using to compile hello.c:
-w: Suppress all warnings. This is bad practice and will be the root of each and every single one of your bugs sooner or later. I've yet to find a good reason to suppress any warning. Anyways, this doesn't matter for this situation, as compiling a hello world program yields no warnings.
-fPIC: Generate ]position-independent code](https://en.wikipedia.org/wiki/Position-independent_code).
-shared: Generate a shared library instead of an executable.
So, you're attempting to execute a shared library, which is not intended to be executed! However, GCC marks the output file with the executable bit. That makes no sense at all... until you meet HP-UX's mmap() implementation.
Seemingly, due to one of HP-UX's features (cough design flaws cough), the whole Unix(-like) family has inherited this convention of shared libraries being marked as executable, even though most of them will SIGSEGV if you actually try to execute them.
The actual cause of the segmentation fault, from the operating system's point of view, is an artifact of the way the Executable and Linkable Format was designed back in the late 1980's.
Curiously, it happens that shared libraries can indeed avoid SEGV'ing upon execution. However, black voodoo, such as the GNU C Library's, shall be performed in order to do so. The consequences of performing such a ritual are agonizing. For instance, you're left with no way to initialize the C runtime, so you have to use direct read()'s and write()'s instead of stdio. Other runtime-supported subsystems, such as malloc() and friends, are out of question as well. Also, (because of no runtime support) there's no main(). You have to define your own entry point instead, and call _exit(0) explicitly.
tl;dr: Directories and symbolic links have nothing to do with the issue. You're attempting to execute a shared library, and, as that's not the expected behavior, you are SIGSEGV'd.
I know that every header file, i.e. string.h, should have an object file in which
there is the proper implementation.
I also know that for GCC and glibc there is a libc.a or libc.so containing object files.
I tried to open libc.a to see if I could find, i.e., string.o but I didn't find it.
Why? Where can I find for every header the correspondent object file?
It may be implementation dependant. A single .h file may correspond to many .o or the opposite, you might have many .h for a single .o
For example, in my libc.a, I can see about one module per string function :
$ ar t libc.a | grep '^str' | sort
strcasecmp.o
strcasestr.o
strcat.o
strchr.o
strcmp.o
strcoll.o
strcpy.o
strcspn.o
strdup.o
strerror.o
strfmon.o
strftime.o
stringlist.o
strlcat.o
strlcpy.o
strlen.o
strmode.o
strncat.o
strncmp.o
strncpy.o
strndup.o
strnlen.o
strnstr.o
strpbrk.o
strptime.o
strrchr.o
strsep.o
strsignal.o
strspn.o
strstr.o
strtofflags.o
strtoimax.o
strtok.o
strtol.o
strtoll.o
strtonum.o
strtoq.o
strtoul.o
strtoull.o
strtoumax.o
strtouq.o
strxfrm.o
well, in my system, libc.so shows up in /lib
[sourav#braodsword temp]$ ls -l /lib/libc*
-rwxr-xr-x 1 root root 1611564 Mar 10 2010 /lib/libc-2.5.so
However, if you're looking for the source code, you'll not find that in .so file, anyway.
Again, don't expect, every header file declaration will have a defferent object file. They are taken together to form the shared library .so.
gcc c89
I am just looking to link against the below shared library.
I am wondering why the programmer has created so many soft-links. The programmer has left the company and I am just wondering what is the purpose.
lrwxrwxrwx. 1 24 Jan 11 11:23 libsofia-sip-ua.so -> libsofia-sip-ua.so.0.6.0
lrwxrwxrwx. 1 24 Jan 11 11:23 libsofia-sip-ua.so.0 -> libsofia-sip-ua.so.0.6.0
-rwxrwxr-x. 1 4728304 Jan 11 11:19 libsofia-sip-ua.so.0.6.0
For what I can understand if the library was to get updated to a newer version you could just soft-link it with the updated version.
But why create libsofia-sip.so.0?
Many thanks for any suggestions,
The filename ending in .so is the one used by the linker (not dynamic linker) when you use the -l option to specify a library you want to search/link. The linker is unaware of other suffixes and won't find them. When the linker opens this file, it finds a different name in the DT_SONAME field of the library's header, usually the name with a single-number suffix. This is the name it will store in the DT_NEEDED field of the new program's dynamic linking header.
The filename ending in .so.N (e.g. N=0 in your case) is the one corresponding to the DT_SONAME in the library file, and it represents a series of library versions which all have a compatible ABI.
The filename ending in .so.N.X.Y is the actual file for the currently installed library version. It's possible for more than one of these to exist, and normally the other symlinks will be setup to point to the most recent version. But old versions are not automatically overwritten this way, so you could manually load an old one with LD_PRELOAD or replace the symlinks if there's a reason you need to downgrade.
Most likely, the library's "real name" is libsofia-sip-ua.so.0. This is encoded into the shared object. The libsofia-sip-ua.0.6.0 name is probably just a name it was installed under.
It was probably the ldconfig program that made the links. I believe it always makes a link for the embedded name if the library file has some other name.
So it probably was not the programmer who wanted these extra links. He, or his library build tool, named the library file a different name than what is embedded inside the library file.
How can I export the libraries that a cmake library depends on, such that an executable depending on that library does not have to manually depend on the dependencies of that library?
That's a bit of a mouthful, so here's an example:
dummy (application) ----> depends on liba
liba ----> depends on libpng
Compiling dummy generates errors:
-- Found LIBPNG
-- Found LIBA
-- Configuring done
-- Generating done
-- Build files have been written to: /home/doug/projects/dummy/build
Linking C executable dummy
../deps/liba/build/liba.a(a.c.o): In function `a_dummy':
/home/doug/projects/dummy/deps/liba/src/a.c:6: undefined reference to `png_sig_cmp'
collect2: ld returned 1 exit status
make[2]: *** [dummy] Error 1
make[1]: *** [CMakeFiles/dummy.dir/all] Error 2
make: *** [all] Error 2
I can fix that by adding this into CMakeLists.txt for dummy:
TARGET_LINK_LIBRARIES(dummy png)
However, dummy has no knowledge of how liba implements its api. At some point that may change to being libjpg, or something else, which will break the dummy application.
After getting some help from the cmake mailing list I've been directed to this example for exporting things:
http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file
However, following that approach leaves me stuck at this line:
export(TARGETS ${LIBPNG_LIBRARY} FILE "${PROJECT_BINARY_DIR}/ALibraryDepends.cmake")
Clearly I'm missing something here; this 'export' command looks like its designed to export sub-projects to a high level; ie. nested projects inside liba.
However, that is not the problem here.
When configuring liba (or any cmake library) I will always generate a list of dependencies which are not part of that project.
How can I export those so they appear as part of LIBA_LIBRARY when I use find_package() to resolve liba?
Using static libraries is not an option (static library for something that links to opengl? no.)
Given your comment to arrowdodger's answer about the fear of
installing something would mess up your system I chose to give
a conceptional comment in form of an answer because of its
length.
Chaining cmake project works via find_package, which looks for
*Config.cmake and *-config.cmake files.
Project A's CMakeLists.txt:
#CMakeLists.txt
project(A)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/AConfig.cmake share/A/cmake
)
#AConfig.cmake
message("Yepp, you've found me.")
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/test-install ..
$ make install
Project B's CMakeLists.txt:
project(B)
find_package(A)
Then
$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/test-install ..
$ make install
results in
...
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Yepp, you've found me.
B found A because it installed AConfig.cmake into a location
where cmake will find it 'share/A/cmake' AND was given the same
value for CMAKE_INSTALL_PREFIX.
Now this is that. Lets think about what you can do in
AConfig.cmake: AFAIK everything you want to. But the most common
task is to pull information about the targets of A via include(),
do some additional find_package invoctions for 3rd party
packages (HINT HINT) and create the variables
A_LIBRARIES
A_INCLUDE_DIRS
What you want to include is a file that was created by
install(EXPORT A-targets
DESTINATION share/A/cmake
)
in A's CMakeLists.txt , where A-targets refers to a global cmake
variable that accumulated all target informations when used in
install(TARGETS ...
EXPORT A-targets
...
)
statments. What is created at make install is
/tmp/test-install/share/A/cmake/A-targets.cmake
which then resides alongside AConfig.cmake in the same directory.
Please take another look at the wiki page on how to use this file
within AConfig.cmake.
Regarding the export() command: This comes handy if your
projects have gotten HUGE and it takes a considerable amount of
time to install them. To speed things up, you want to use what's
in A's build/ directory directly. It's an optimization and also
explained in the wiki. It still works via find_package(), see
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:export
But I strongly suggest that you go for the usual make install
route for now.
I found my own solution to this problem using the accepted solution above, which I leave here for others:
In liba/CMakeLists.txt:
# Self
set(A_INCLUDE_DIRS ${A_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/include")
set(A_LIBRARIES ${A_LIBRARIES} "${PROJECT_BINARY_DIR}/liba.a")
# Libpng
FIND_PACKAGE(libpng REQUIRED)
set(A_INCLUDE_DIRS ${A_INCLUDE_DIRS} ${LIBPNG_INCLUDE_DIRS})
set(A_LIBRARIES ${A_LIBRARIES} ${LIBPNG_LIBRARIES})
ADD_LIBRARY(a ${SOURCES})
# Includes
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
# Allow other projects to use this
configure_file(AConfig.cmake.in "${PROJECT_BINARY_DIR}/AConfig.cmake")
In liba/AConfig.cmake:
set(A_LIBRARIES #A_LIBRARIES#)
set(A_INCLUDE_DIRS #A_INCLUDE_DIRS#)
In dummy/CMakeLists.txt:
FIND_PACKAGE(A REQUIRED)
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(dummy ${A_LIBRARIES})
This yields an AConfig.cmake that reads:
set(A_LIBRARIES /home/doug/projects/dummy/deps/liba/build/liba.a;/usr/lib/libpng.so)
set(A_INCLUDE_DIRS /home/doug/projects/dummy/deps/liba/include;/usr/include)
And a verbose compile that reads:
/usr/bin/gcc -std=c99 -g CMakeFiles/dummy.dir/src/main.c.o -o dummy -rdynamic ../deps/liba/build/liba.a -lpng
Which is exactly what I was looking for.
If liba doesn't provide any means to determine it's dependencies, you can't do anything.
If liba is library developed by you and you are using CMake to build it, then you should install libaConfig.cmake file with liba itself, which would contain necessary definitions. Then you include libaConfig in dummy's CMakeLists.txt to obtain information about how liba have been built.
You can look how it's done in LLVM project, relevant files have cmake.in extension
http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/modules/
In the end, in dummy project you should use
target_link_libraries( ${LIBA_LIBRARIES} )
include_directories( ${LIBA_INCLUDE_DIR} )
link_directories( ${LIBA_LIBRARY_DIR} )
If that liba is used only by dummy, you can build it from single CMake project. This is more convenient, since you don't need to install liba each time you recompile it and it will be rebuilt and relinked with dummy automatically every time you run make.
If you liked this approach, the only thing you should do - define in liba' CMakeLists.txt variables you need with PARENT_SCOPE option (see set() command manual).
Finally, you can use shared libs, .so's don't have such problem.
So I start reading the book http://lwn.net/Kernel/LDD3/ to write device driver
The problem is the book used 2.6.10 while I'm using 2.6.35.X (on Ubuntu) and "config.h" is missing. I googled the problem and it turned out that config.h is removed.
http://stephane.lesimple.fr/wiki/blog/kernel_2.6.18_linux_config.h_problem suggests 3 solutions and the first 2 don't work to me ( I don't have autoconf.h ). The 3rd solution is the one that is over my head. If anyone can explain the 3rd or has other solutions, I'd appreciate.
Thanks
All -imacros file and -include
file options are processed after all -D and -U options1.
Each (of the three) option is a way of pointing GCC to a text file with a list of preprocessor defines.
To use option 3, -imacros a_file , there is still a need for the file a_file , (ie: autoconf.h), the file with the macros or configuration definitions. On this system it's /usr/src/linux/include/generated/autoconf.h
l /usr/src/linux
lrwxrwxrwx 1 root conman 23 Nov 29 19:37 /usr/src/linux -> linux-2.6.35-gentoo-r12
As you can see, this file can occur in 2.6.35. It seems that maybe configuringi the kernel makes this file; because the content of this file looks tailored to the current kernel. This looks like a file declaring which drivers are compiled-in(as apposed to compiled as modules).
So:
First check for the file find /usr/src/linux/. -name autoconf.h
If it is not there, then configure the kernel (then check again)
Change CFLAGS in the device driver's Makefile to include -imacros /usr/src/linux/include/generated/autoconf.h
CFLAGS+=-imacros /usr/src/linux/include/generated/autoconf.h
Comment out #include <config.h> from the driver sources.
1 "3.11 Options Controlling the Preprocessor," GCC Reference