I am writing a Makefile placed in the root directory of my project.
Here is my project directory tree:
project:
Makefile
README
assets/
build/
src/
Actually in Makefile I'm prepending each file with a variable to tell to gcc where find the file:
gcc -c $(SOURCE_DIR)file.c
I'd like to compile .c source files placed in the directory src without change the working directory in the Makefile or prepending the SOURCE_DIR to each file that I have to compile.
Is there any way to do this?
P.S. I've read manual (man gcc) looking for some gcc options. I found that -L or -l could help me, but I didn't understand their usage.
The standard way, like the autotools do, would be write a Makefile in src dir, and then in your main Makefile call that sub Makefile:
programs:
make -C $(SOURCE_DIR) the_program
This case, you can build the program no matter you are in the main directory or in the src directory.
Related
In my working directory there are main.c and a folder named lib with libtest.dll in it.
I use
$ gcc main.c -ltest -L ./lib -Wl,-rpath=./lib
to compile, and the compilation process is no problem (no warning and error). But when i run a.exe the system remind
D:/MYSY2/home/user/code/a.exe: error while loading shared libraries: libtest.dll: cannot open shared object file: No such file or directory
So why the library can be found when compiling but not when running?
Shared libraries on Windows are .dll files and the are located by looking in the same folder as the running .exe file, or if that doesn't work by looking in the locations specified by the PATH environment variable.
So the best solution is to copy the .dll file(s) in the same location as the .exe file(s).
For distribution of your application you can use copypedeps -r from https://github.com/brechtsanders/pedeps to copy the .exe file along with any dependency .dll files, in case you are not certain which files are needed.
So I am making a C application and I have all the library files .so , .a etc in a ./lib directory in the same directory as my C application.
I am compiling my C application with the -L./lib flag.
But it seems to me that gcc still looks for libraries within /usr/lib /usr/local/lib etc .
Is there a way to force gcc to only look for library files in my ./lib directory?
So if I remove the ./lib folder the application won't compile because it can't find the libraries.
I have a C application using CMake to generate Makefiles on Linux. The application contains .c as well as .proto files. Now I need to genearte .pb-c.c and .pb-c.h using protoc command in the CMakeLists.txt so that when I do cmake . the cmake generates the corresponding .pb-c and .pb-h. The protoc is used as:
execute_process(COMMAND bash -c "${PROTOC_PATH} --c_out=${CMAKE_CURRENT_SOURCE_DIR}/ --proto_path=${PROTO_DIR}/ ${PROTO_DIR}/*.proto")
The problem is that my protoc binary and related .so file is not in /usr/bin and /usr/lib or /usr/local/bin and /usr/local/lib. They are in a directory inside the project - $HOME/project-name/dependencies/bin/protoc and $HOME/project-name/dependencies/lib/libprotobuf.so.12
Due to this I am getting error - error while loading shared libraries: libprotobuf.so.12: cannot open shared object file: No such file or directory
But if I give the command as
execute_process(COMMAND bash -c "protoc--c_out=${CMAKE_CURRENT_SOURCE_DIR}/ --proto_path=${PROTO_DIR}/ ${PROTO_DIR}/*.proto") and run cmake . then it works fine as linker is able to get the .so file from /usr/lib
Mentioned below is a part of my CMakeLists.txt file
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath=${PROTOC_LIB_PATH} -L${PROTOC_LIB_PATH} -lprotobuf")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-rpath=${PROTOC_LIB_PATH} -L${PROTOC_LIB_PATH} -lprotobuf")
execute_process(COMMAND bash -c "${PROTOC_PATH} --c_out=${CMAKE_CURRENT_SOURCE_DIR}/ --proto_path=${PROTO_DIR}/ ${PROTO_DIR}/*.proto")
But it's not working due to aforementioned error.
Also for those who might say it's a duplicate I have looked into and tried the following SO questions:
Turning on linker flags with CMake
I don't understand -Wl,-rpath -Wl,
CMake link to external library
Does cmake have something like target_link_options?
CMAKE RPATH not working - could not find shared object file
https://serverfault.com/q/279068/435497
How to add linker flag for libraries with CMake?
https://serverfault.com/a/926072/435497
If you do not have a special use case, you do not need to call protoc yourself. Let CMake do this for you.
Have a look at: https://cmake.org/cmake/help/v3.16/module/FindProtobuf.html
and Cmake : find protobuf package in custom directory
I found this link which has a script showing how to create a PROTOBUF_GENERATE_C function which can then be used to generate the .pb-c abd .pb-h files.
From the above script I got the idea to make use of find_program which is similar to find_library in a way that it lets you pass the PATHS/PATH option so that CMake looks for the required program in the mentioned path.
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.
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.