How to make linked readline library relocatable in Cmake - c

Firstly, I am not sure if the title exactly words my question well but after three days of searching the web and SO for no working answer, please bear with me.
So the problem is that I have a C application where CMake is the build system. This application relies on libreadline and I can correctly find and link with it using the snippet below:
find_library(READLINE_LIBRARY readline REQUIRED)
target_link_libraries(myExe PRIVATE "${READLINE_LIBRARY}")
The problem is that when I build the application on a system with say for example libreadline.so.8 which is the version 8 and move the application to another system that only has libreadline.so.7 or none available, I'll have to install the missing library before I can run the application. This make for a very bad user experience.
I have tried setting the #rpath before the add_executable and add_library with:
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:$ORIGIN")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
The problem is that while that correctly sets the #rpath for a shared library which forms part of the project, it doesn't do the same for libreadline. Also even if for any reason I am able to get it to work, I don't know how to get call to find_library return a relocatable library (meaning I can't bet that the libreadline.so.8 was build with -fPIC or not).
Whatever I do, I can't get a local copy of libreadline in my build output directory.
Also note that this problem exists on OSX as well just using the Linux example for simplicity.
On OSX when I inspected the executable with tool -l myExe, I noticed that only the Load Command section for the shared executable which is part of my project correctly uses #rpath while the editline (OSX deadline seems to just be an editline) looks like this:
Load command 14
cmd LC_LOAD_DYLIB
cmdsize 56
name /usr/lib/libedit.3.dylib (offset 24)
Any help will be appreciated. I'm quite stuck. But one thing I'm certain of it that I have seen applications that does this which means it's very possible.

Related

Compiling in a dynamic C library (dylib) into a program on OS X

I've written a little C program which uses libusb. Now I want to distribute this program to "normal" (not dev) Mac OS X computers. But when I ported the compiled file to a test machine I got the following error:
dyld: Library not loaded: /opt/local/lib/libusb-0.1.4.dylib
Referenced from: /Users/kitty/myprogram
Reason: image not found
Trace/BPT trap: 5
When I copy the files (works only with all the files)
/opt/local/lib/libusb-0.1.4.dylib /opt/local/lib/libusb-1.0.a
/opt/local/lib/libusb.a
/opt/local/lib/libusb-1.0.0.dylib /opt/local/lib/libusb-1.0.dylib
/opt/local/lib/libusb.dylib
from my machine to the target machine the program works flawlessly.
But I really want to create or compile everything into a single executable. How is this possible?
Using -static while compiling does not work since not all libraries can be compiled into the final app statically (see this SO question here).
So how can I make a single neat little application file?
You can convert a static library to a dynamic library, but I'm not aware of a way to do the reverse as you want it.
If you're building an app with a bundle, you need to put the library you want to distribute inside your bundle, in the Frameworks directory, and link against that.
If you are not building a bundle-based app, just a single binary, you may need to provide instructions for your users on how to install the library on their system (e.g. via Homebrew).
Here's how you do it for bundle-based apps:
Apple has a document about run-path dependent libraries but doesn't actually explain how to set this up for a newbie.
Here's how it should work:
Add the libusb.dylib you want to use to your project.
It should automatically get added to your "Link Binary with Libraries" phase in your project's "Build Phases". If not, add it here.
Add a new "Copy Files" build phase.
In the "Destination" drop-down box, select "Frameworks". This is the
Frameworks directory in your app's final bundle.
Then press the "+" icon in that copy build phase and add your library.
If you had any manual linking options like -L/usr/local/lib and -lusb, remove them.
Clean and build.
When you now look into your app bundle, you'll see that the library is copied to <bundle_path>/Contents/Frameworks/. You can now start the app from wherever you want, the dynamic link loader knows it needs to look at <path_to_binary>/../Frameworks/ to find your library.
But: you may need to rebuild your libusb to have the install_name set to #rpath/../Frameworks/libusb.dylib or use the install_name_tool CLI tool fix that path for your copy of libusb.dylib that you added to your project.

Virtual environment for C library development

Original
I am looking for a way to create a non-isolated development environment for a C-library.
I will most likely use cmake to build the library and my IDE is a simple text editor.
The problem now is that I do not only create the library but also some sample "applications" using the library.
Therefore I need to install the library's headers and the shared object (I'm using GNU/Linux) somewhere and I do not want to install it to /usr/local/lib or (the even worse) /usr/lib.
Is there a way to create a virtual environment similar to python's pyvenv (and similar) where I can install the everything to but still have access to the host libraries?
Also I do not want to rewrite my $PATH/$LD_LIBRARY_PATH, setup a VM, container, or chroot.
The usage would then look like:
# switch to environment somehow
loadenv library1
# for library
cd library
make && make install
# for application
cd ../application1
make && ./application1
Is this possible?
Edit 1
So basically my directory structure will look like this:
library/
library/src/
library/src/<files>.c
library/include/<files>.h
application/
application/src/
application/src/<files>.c
First I need to compile the library and install the binary and header files.
These should be installed in a fake system-location.
Then I can compile the application and run it.
Edit 2
I thought a bit about it and it seems all I need is a filesystem sandbox.
So basically I want to open up a shell where every write to disk is not committed to the filesystem but rather temporarily saved in e.g. a ramfs/tmpfs just to be dropped when the shell exits.
This way I can exactly test how everything would behave if compiled, deployed and executed on the real machine without any danger to existing files or directories and without accidentally creating files or directories without cleaning them up.
You don't really need to 'install' the library, you can work in the development tree.
(1) for compilation all you need to do is use -I flag to specify where the libraries header files are, and this can be a relative path, for example in your case you could do -I../../library/include
(2) for linking you need to tell the linker where the library is located at, you can use the -L flag append to the library search order.
(3) for testing the application, you are correct that the application needs to be able to find the library. You have a couple of options:
(a) make sure the library and the executable are in the same directory
(b) you can temporarily modify your LD_LIBRARY_PATH, in your current shell only, for testing:
export LD_LIBRARY_PATH=abs_path_to_library:$LD_LIBRARY_PATH
note that this will only effect the current shell (command terminal) you are working in. Any other shells you may have open, or open later will have your normal LD_LIBRARY_PATH. I know you specified that you don't want to modify your PATH or LD_LIBRARY_PATH, but being local to the shell that the command is executed it is a nice, easy way to do this.
(c) embed the path to the library in the client executable. To do this you need to pass an option to the linker. The command for gcc is:
-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)
see this how-to

cmake install multiple version of the same library

I am trying to have a scheme with my library that is coherent and usable/reusable.
I work in a team where we work with continuous integration but sometimes I need to use old version of the same library. That's because some part of the software are not updated for using the new version.
I'm actually in the middle of a headache understanding how to use cmake for having something like this:
PATH/Library/Processor/Library_X/Version/static_library_and_includes
Where Library is a common name where to put my stuff
Processor could be attiny24, atmega, lxpXXXX, etc
Library_X is the name of the library
Version a progressive number from 0 to X
static_library_and_includes the static libraries built within that cmake module and the include files needed for using it.
How can I do this using cmake?
I work with different microprocessor crosscompiling with gcc. This is not a problem.
I work with static library, this is not a problem.
I can install them in the right directory. Not a problem
I can't ask the executable to link to the right .a file. Sometimes cmake pick the right one, sometimes not.
Can you please give me a hint on how you guys do it?
thank in advance
Andrea
See the search paths here: https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure .
CMake will find packages in directories named name*, so you can install to <prefix>/FizzBuzz-1.0.0 and <prefix>/FizzBuzz-2.0.0.
As long as each as a correct ConfigVersion.cmake file, it should do what you want.

About linking files using Mac terminal

Okay here goes, I'm completely new at this, started learning the terminal just about 2 days ago. I'm slowly but surely getting the hang of it, now I'm stuck on this and I've been trying to fix it for a good hour. It's a rather simple question as I am a newby.
I have a C file in my desktop and a Header file in a folder in my desktop. I'm including that header in my C file. I have to link them (currently doing a tutorial, it tells me to link, but doesn't show me how).
You have a couple of options. First, you will need to install the software development environment - it's called Xcode. I think you can get it for free on the AppStore, if not Google it.
Then you need to decide if you want to develop and compile graphically in the Xcode Integrated Development Environment. If you do, start Xcode and create a new project and open your C file and change the "include path" to match the location of your header file. Then click "Build" and "Run"
If you want to do things at the commandline, you'll need to install "Xcode Command Line Tools" - Google it. That will give you a compiler. Then you can compile. I'm not certain which compiler you will get - it could be "llvm" or "gcc" or something else, but the command you are looking for will be something like:
gcc -o prog -I /path/to/HeaderFileFolder yoursourcecode.c
which will give you a program called "prog" that you can run by typing
./prog
You are likely confusing two different concepts. The "link" mentioned in the tutorial is probably talking about turning the compiled objects into a single executable. See http://www.cprogramming.com/compilingandlinking.html for an explanation of what linking means in this context.
What you've provided examples of doing is file system linking, which is totally unrelated.
Providing more details on the tutorial could help refine this answer.

How would one compile a program for the Coldfire toolchain?

I'm trying to compile a simple hello world application to be run on uCLinux (2.4) which is running on a board with a Freescale Coldfire (MCF5280C) processor...and I'm not quite sure what to do here.
I know I need to compile with the correct version/tools from Freescale to target this hardware, so I downloaded and installed the Coldfire tool chain and verified that one I have is for my target:
mike#linux-4puc:/usr/local/m68k-elf/bin> ./gcc -v
Reading specs from /usr/local/lib/gcc-lib/m68k-elf/2.95.3/specs
gcc version 2.95.3 20010315 (release)(ColdFire patches - 20010318 from http://fiddes.net/coldfire/)(uClinux XIP and shared lib patches from http://www.snapgear.com/)
I tried a simple gcc "file" type command:
mike#linux-4puc:/home/mike> /usr/local/m68k-elf/bin/gcc test.c
/usr/local/m68k-elf/bin/ld.real: cannot open crt0.o: No such file or directory
collect2: ld returned 1 exit status
Which does not work at all.. so it's clearly more complex that than. The output almost looks like it wants me to build the tool chain before I use it?? Anyone ever done this before? Not sure what I need to do or if I just need some flags.
You might also try seeing if you have a command called m68k-elf-gcc or something along those lines. This is a common naming for cross-compilers.
As for your problem, it sounds like there is something wrong with your compiler setup. crt0.o is the object file that contains C-runtime setup code. The linker (what is actually giving the error) should know where this file is if setup properly.
When you installed you should have run make install as the last step without having modified anything since the make step. The configuration step will setup certain variables and such based on the path where it's supposed to be installed.
Where did you get a FreeScale toolchain? I took a look at their site and it seemed only third parties supplied C++ cross-compilers. In the toolchain I get from NetBurner (for use with their hardware) the crt0.o file exists under the gcc-m68k\m68k-elf\lib directory.

Resources