Static library not linking when using -l and -L flags? - c

So, I have a static library called libtree-sitter.a that I'm trying to use. Here is the compilation command from the documentation:
clang \
-I tree-sitter/lib/include \
test-json-parser.c \
tree-sitter-json/src/parser.c \
tree-sitter/libtree-sitter.a \
-o test-json-parser
The above command successfully compiles and the executable works correctly. I tried changing the loading of the static library into flags so I could make my build system more generic. My changes are below:
clang \
-I tree-sitter/lib/include \
test-json-parser.c \
tree-sitter-json/src/parser.c \
-o test-json-parser \
-Ltree-sitter -ltree-sitter
This compiles, but running the executable gives this error:
dyld: Library not loaded: /usr/local/lib/libtree-sitter.0.dylib
Referenced from: /Users/jason/Downloads/tree sitter test/test-json-parser
Reason: image not found
Can someone please explain the difference between those two examples? From my understanding of -l and -L, it should still find the library in the same place. What is an equivalent combination of flags so I can make loading libraries more generic and easily integrable with Makefile templates (I am using this one)? Thanks for reading.

Your error message says:
dyld: Library not loaded: /usr/local/lib/libtree-sitter.0.dylib
Referenced from: /Users/jason/Downloads/tree sitter test/test-json-parser
Reason: image not found
This gives you several hints about what is happening: It says that it doesn't find libtree-sitter.0.dylib in directory /usr/local/lib which indicates that you have not specified a -L option to search in the subdirectory you say.
First of all, I recommend you to execute clang with option -v to show what command line is it using to call the linker. This will probably don't show the -L option you specified and it's argument.
My guess is that you are using that command line in some script that is deleting some of the \ chars (or you have a space after the \, and you are getting a new line cutting your command line before the linker options. Check this.
The linker you are using will check all directories specified in -L options before any of the system directories, for a file called libyourLibraryName.number.dylib, if it doesn't find, will try libyourLibraryName.a, and then it will try the next directory in the list. If you call the compiler with the -v option you will get the set of options it is using to call the linker. Please, it would be nice if you include that in your question.

Related

How to load C library functions into assembly, and use assembly library functions in another C or assembly project

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.

Compiling c program with dependencies, h and h0 files

I am trying to compile the gjh solver - written in C - into an executable file in windows. It is available on netlib
I downloaded the c file and am using gcc compiler via WinGW on windows' command prompt. Trying to compile the gjh.c file directly gave me an error that says:
gjh.c:33:21: fatal error: getstub.h: No such file or directory
#include "getstub.h"
compilation terminated.
I assumed that compiling gjh.c requires the dependency getstub.h.
getstub.h is not the only dependency required, there are other dependencies, namely: arith.h, asl.h, funcadd.h, and stdio1.h. All of these files are available on the same link where I found getstub.h. However, arith.h0 and stdio1.h0 are available instead of arith.h and stdio1.h.
Are these files the same? I tried to rename the .h0 files to .h and tried to compile gjh.c, but I got this error:
collect2.exe: error: ld returned 1 exit status
Are the two files the same? If not, is there any way for me to compile the gjh solver successfully into an .exe?
If that's the only problem in compiling, try using the -I switch in gcc:
gcc -I/my/path/to/include/files -o gjh gjh.c
the -I switch hints to gcc where to find your #include files.
I am not sure about the stdio1.h. I think your approach to rename is OK but that reference to external functions such as Sprintf. You need to link with a library defining that. If you know where it comes from, use the -L and -l switch in gcc for that:
gcc -I/my/path/to/include/files -L/my/path/to/library -lnameoflibrary \
-o gjh gjh.c

eCos : Compile and Run sample application on Linux

I have installed eCos OS on a linux system (Ubuntu 13.02). After installation, the eCos files are located in opt/ecos.
As I read the eCos tutorial, I see hello.c is stored in opt/ecos/ecos-3.0/examples/hello.c (And I notice that maybe all main eCos system files store in the ecos-3.0 directory).
I have followed the eCos tutorial found on the official website, but I still cannot successfully compile hello.c.
More detail. When I try to run :
$ export INSTALL_DIR=BASE_DIR/ecos-work/arm_install
$ TARGET-gcc -g -IBASE_DIR/ecos-work/install/include hello.c \
-LBASE_DIR/ecos-work/install/lib -Ttarget.ld -nostdlib
I get the error : TARGET-gcc : command not found
I have tried some other tutorials, but I'm still having issues (too messy to list here).
I am looking for step-by-step instruction on compiling hello.c in eCos system. I see the eCos manual lacking in this area.
Thanks :)
It appears that you've missed a subtle convention in the eCos documentation. Items in italics are provided by you! They are variables.
The documentation mentions this here:
Note: Remember that when this manual shows TARGET-gcc you should use
the full name of the cross compiler, e.g. i386-elf-gcc, arm-elf-gcc,
or sh-elf-gcc. When compiling for the synthetic Linux target, use the
native gcc which must have the features required by eCos.
Replace TARGET with the appropriate value and BASE_DIR with (I think, in your case) /opt/ecos. You should verify the include directory before moving forward:
$ ls -l /opt/ecos/ecos-work/install/include
If that doesn't list directory contents, then you simply need to locate ecos-work
The Ecosconfig on Windows and Linux Quick Start section of the docs has you create the BASE_DIR directory (below is a snippet that I am quoting ... italics will not display).
$ mkdir BASE_DIR/ecos-work
$ cd BASE_DIR/ecos-work
So, this could be the correct invocation.
$ export INSTALL_DIR=/opt/ecos/ecos-work/arm_install
$ arm-elf-gcc -g -I/opt/ecos/ecos-work/install/include hello.c \
-L/opt/ecos/ecos-work/install/lib -Ttarget.ld -nostdlib
you need to do
# source /opt/ecos/ecosenv.sh
Then you can try to compile by changing TARGET=
$ TARGET-gcc -g -IBASE_DIR/ecos-work/install/include hello.c \
-LBASE_DIR/ecos-work/install/lib -Ttarget.ld -nostdlib

Clang not creating object files when using plugin

I'm trying to use clang++ instead of g++ to create object files that will later be linked by the gnu linker.
I'm am able to do this successfully using native clang++, but when I use clang++ with a plugin, I get a link error:
clang: error: linker command failed with exit code 1 (use -v to see invocation)
That's okay! I just need the object files! However, when I specify -S or -c I do not get any object file, even if I use .o to explicitly specify an output file.
I am unable to do this even with clang's example plugins.
How can I get clang to give an object file?
Much Thanks!
I had this same issue. For me, replacing "-plugin" with "-add-plugin" on my command line fixed the problem. I'm not sure what the difference is or why it worked, but it did.
Also, if you are using "-cc1" on the command line, try removing it and prefixing every plugin specific argument with "-Xclang ", i.e. "clang -Xclang -load -Xclang plugin.so -Xclang -add-plugin -Xclang pluginName". Again, I'm not sure why -cc1 wasn't working for me, but it wasn't and this fixed it.

Shared library in /usr/local/lib not found

I don't get it. I usually install third party software into /usr/local so libraries are installed into /usr/local/lib and never had problems linking to these libraries. But now it suddenly no longer works:
$ gcc -lkaytils -o test test.c
/usr/bin/ld.gold.real: error: cannot find -lkaytils
/usr/bin/ld.gold.real: /tmp/ccXwCkYk.o: in function main:test.c(.text+0x15):
error: undefined reference to 'strCreate'
collect2: ld returned 1 exit status
When I add the parameter -L/usr/local/lib than it works but I never had to use this before. Header files in /usr/local/include are found without adding -I/usr/local/include.
I'm using Debian GNU/Linux 6 (Squeeze) which has an entry for /usr/local/lib in /etc/ld.so.conf.d/libc.conf by default and the ldconfig cache knows the library I'm trying to use:
k#vincent:~$ ldconfig -p | grep kaytils
libkaytils.so.0 (libc6,x86-64) => /usr/local/lib/libkaytils.so.0
libkaytils.so (libc6,x86-64) => /usr/local/lib/libkaytils.so
So what the heck is going on here? Where can I check which library paths are searched by gcc by default? Maybe something is wrong there.
gcc -print-search-dirs will tell you what path the compiler checks. /usr/local/lib is simply not among them, so your compile time linker (in this case the new gold ld from binutils) doesn't find the library while the dynamic one (ld-linux.so which reads the cache written by ldconfig) does. Presumably the builds you've done previously added -L/usr/local/lib as necessary in their makefiles (usually done by a ./configure script), or you installed binaries.
This is probably an issue of environment variables - you have something set that's including /usr/local/include but not /usr/local/lib
From the GCC mapage on environment variables
CPATH specifies a list of directories to be searched as if speci‐
fied with -I, but after any paths given with -I options on the com‐
mand line. This environment variable is used regardless of which
language is being preprocessed.
and
The value of LIBRARY_PATH is a colon-separated list of directories,
much like PATH. When configured as a native compiler, GCC tries
the directories thus specified when searching for special linker
files, if it can’t find them using GCC_EXEC_PREFIX. Linking using
GCC also uses these directories when searching for ordinary
libraries for the -l option (but directories specified with -L come
first).
try "printenv" to see what you have set

Resources