first off, this is a programming assignment so you are aware.
Anyhow, what I am trying to do is include a shared library I wrote (a linked list from a previous project) in with my own shell I am writing. The issue I incur is that when I compile using my Makfile, the compile is successful. Then when I try to run my executable (let's say it's called prog), I get the following:
[terminal]# ./prog
./prog: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory
The following is my file structure for reference:
include
|_
common.h
List.h
Node.h
lib
|_
libmylib.a
libmylib.so
libsrc
|_
Makefile // This makefile builds the library correctly and puts it in lib via 'make install'
List.c
List.h
Node.c
Node.h
common.h
Makefile
prog.c
Here is my main Makefile
CC=gcc
CFLAGS=-g -Wall -Llib
LIBS=-lreadline -lncurses -lmylib
PROGS=library prog
all: $(PROGS)
library:
cd libsrc; make install
prog: prog.o
$(CC) $(CFLAGS) -o $# $< $(LIBS)
clean:
cd libsrc; make installclean
/bin/rm -f *.o $(PROGS) a.out core *.log
Any help or advice is appreciated, thanks!
The runtime dynamic linker does not know where to find your shared library.
Two options:
Set the LD_LIBRARY_PATH environment variable to include the absolute path to your lib directory:
LD_LIBRARY_PATH=/path/to/lib
export LD_LIBRARY_PATH
Hard-code the absolute path to your lib directory in the executable image by passing -R/path/to/lib to the linker (e.g. in your makefile, CFLAGS=... -Llib -R/path/to/lib.
The first option is flexible, in the sense that the shared library can be installed anywhere and even moved to another location, and the executable won't break as long as the environment variable is updated accordingly. But it does require the user (or system administrator) must set up the environment correctly.
The second option does not allow the shared library to be moved from its predefined installation directory, but removes the dependencies on a correctly setup environment.
Note that you won't need to do either if you install your shared library in a standard system-specific location (e.g. /usr/lib or /usr/lib64 on Unix/Linux) as the runtime linker will search such locations automatically.
Related
Supposing I have main.c main.o libheymath.so in current directory. I want to link them together to generate an executable file. I use command "g++ -o main main.o -L./ -lheymath" to realize that. But I don't know why I should indicate the library directory and name. As far as I know, when I run "./main" the system will load the shared library into memory in specific directories such as /lib and /use/lib and directories specified in LD_LIBRARY_PATH etc. but not what I have indicated. So what's the purpose of "-L./ -lheymath"?
working directory files:
main.c, main.o, libheymath.so
command:
g++ -o main main.o -L./ -lheymath
./main
-L allows to indicates a path where to look to find lib(s) at link time (it is not 'saved' in the produced executable to be reused when you will launch the executable)
-l indicates a lib you want to link with, this allows to check if some symbols are missing or not and to know the list of libs to load when you will launch the executable.
When you link the path of these libs is not saved into the executable because both executable and libs can be moved after the link (and may be installed on an other host)
Note LD_LIBRARY_PATH is used when you start an executable to find the dynamic libs, it is not used when you link objects/libs to make an executable
I am building a Swift command-line application with references to a third party library (netcdf) in /usr/local/lib. I have a bridging header in the project and when making the appropriate calls, there are no errors. So I'm fairly confident that the #include is being found in the bridging file.
In Build Settings, I have added /usr/local/lib to Library Search Paths and -lnetcdf to Other Linker Flags.
However I am seeing a link failure. Specifically I am seeing an undefined symbols message. Looking at the ld command shown when I click on the error, I can see that -L/usr/local/lib is there. However the -lnetcdf is not.
What else do I have to do to get the -l into the link command?
After three hours of trying to resolve this, I eventually thought 'stuff it' and spent about 15 mins writing a Makefile.
CLIBS=-lnetcdf
SWFILES=main.swift NCUtil.swift
SWIMPORT=-import-objc-header ../GSIP-Bridging-Header.h
SWIFTLIB=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx
SLIBS=-lSystem -lobjc
GSIP: main.o NCUtil.o
ld $^ -arch x86_64 -L $(SWIFTLIB) $(SLIBS) $(CLIBS) -rpath $(SWIFTLIB) -macosx_version_min 10.10 -no_objc_category_merging -o $#
%.o: %.swift
swiftc -c $(SWFILES) -target x86_64-apple-darwin14.5.0 -I /usr/local/include -I /usr/include $(SWIMPORT) -module-name=GSIP
.PHONY: clean
clean:
rm -f *.o GSIP
There is in fact another solution. Using the Finder menu to Go -> Go to Folder, go to the directory where the dylib is located. Then from Finder, drop and drag the dylib into your project. Probably a wise idea to use a reference rather than make a copy of the file.
This resolved all my link errors!
Here's a sample SConscript file:
env = Environment()
hello_lib = env.SharedLibrary('hello', ['libhello.c'])
exe = env.Program('main', ['main.c'], LIBS=hello_lib)
env.Install('/usr/lib', hello_lib)
env.Install('/usr/bin', exe)
env.Alias('install', '/usr/bin')
env.Alias('install', '/usr/lib')
It builds one shared library, and one executable linked to that library:
$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gcc -o libhello.os -c -fPIC libhello.c
gcc -o libhello.so -shared libhello.os
gcc -o main.o -c main.c
gcc -o main main.o libhello.so
scons: done building targets.
Now, the issue is the created executable will not find the shared library when running it from the project directory,
which is quite natural, since neither the LD_LIBRARY_PATH env variable is set, or
any RPATH is set in the executable:
[fedora 00:07:10 2 ~] $ ./main
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
I can always set the LD_LIBRARY_PATH variable while developing, but this becomes cumbersome if the project has a directory hierarchy with several shared libraries in sub_directories.
The GNU autotools/libtool solves this by automagically set the RPATH of the executable to wherever the shared libraries are built in the project directory, which allows for easy running/testing the executable while developing. And it relinks the executable when installing it to leave out those RPATH which arn't needed anymore.
Is there anything similar to what autotools does that can be done with scons to ease testing the executables while developing ?
Is there any recommended way to build applications using shared libraries with scons, that makes it easy to run the executable from the build directory ?
You could modify each of the SConscript files which produce libraries, like so:
hello_lib = env.SharedLibrary('#/lib/hello', ['libhello.c'])
All of your shared libraries are now located in a single directory.
The SConscript which produces an executable becomes:
exe = env.Program('main', ['main.c'], LIBPATH='#/lib', LIBS=hello_lib)
Then you will be able to set LD_LIBRARY_PATH to $PWD/lib.
It looks like you are looking for the RPATH option in scons.
From the wiki page, the RPATH is described as scons as the following.
A list of paths to search for shared libraries when running programs.
Currently only used in the GNU linker (gnulink) and IRIX linker
(sgilink). Ignored on platforms and toolchains that don't support it.
Note that the paths added to RPATH are not transformed by scons in any
way: if you want an absolute path, you must make it absolute yourself.
I've made a C program that uses libsndfile to extract some data from audio files.
What possibilities are there to make the program as portable as possible, preferably without requiring root access when installing?
Libsndfile is not available at the target machines, so i need to somehow package it with my program. Is there a way to statically link the library? I've also looked at some Autotools tutorials, but I'm not sure how to proceed.
I can compile without a hitch on my dev machine, where I installed the libraries using the package manager: apt-get install libsnfile1-dev
The makefile is very simple:
CFLAGS=-std=c99 -Wall -pedantic -g
CLIBS= -lsndfile -lm
BIN=audiodecode
CC=gcc
MAIN=main.o
FILES=
OBJS=$(FILES) $(MAIN)
.PHONY: all
all: clean $(OBJS)
$(CC) $(CFLAGS) -o $(BIN) $(OBJS) $(CLIBS)
.PHONY: clean
clean:
rm -f *.o $(BIN)
A lot of packages bundle their dependencies. Examples: rsync (contains a bundled libpopt), gnupg (contains a bundled libz). Other dependencies commonly bundled are gettext or glib.
For inspiration look at how these popular open source projects do it.
Put the content of http://www.mega-nerd.com/libsndfile/files/libsndfile-1.0.25.tar.gz into a subdir and add apropriate rules to build the the subdir first.
Untested sample code:
OBJS += libsndfile/libsndfile.a
libsndfile/libsndfile.a:
cd libsdndfile && ./configure --enable-static && $(MAKE)
For Bonus points add a configure script, that check if the system has already installed libsndfile and link to it dynamically.
So I wrote a program to run on a Tp-link device running OpenWrt Attitude Adjustment 12.09.
I wrote the makefiles successfully in the /OpenWrt-SDK../package/myprogram/src/Makefile and it all ran smoothly when I did a 'make'.
Now I added threads in my program so I configured the Makefile like this:
# build myprogram executable when user executes "make"
LDFLAGS=-pthread
myprogram: myprogram.o
$(CC) $(LDFLAGS) myprogram.o -o myprogram
myprogram.o: myprogram.c
$(CC) $(CFLAGS) -c myprogram.c
# remove object files and executable when user executes "make clean"
clean:
rm *.o myprogram
and when I 'make' inside the package/myprogram/src folder it compiles successfully and runs just fine on my PC.
Now when I go to the root OpenWrt-SDK directory to 'make' I get a missing dependencies error:
Package myprogram is missing dependencies for the following libraries:
libpthread.so.0
So what do I need to do to include these dependencies?
I went to my OpenWrt-SDK root and tried:
./scripts/feeds search libpthread
And I got this result:
./scripts/feeds search libpthread
Search results in feed 'trunk':
libpthread POSIX thread library
Should I install that or is that not it? I do not know if I am doing something else wrong.
I will appreciate any help! Thanks.
Under package definition add
DEPENDS:=+libpthread