Clang linker finding some symbols but not others - node.js

In my .nim code, I'm using the header pragma to include symbols from /usr/local/include/node/node_api.h (which then includes /usr/local/include/node/js_native_api.h).
proc napi_create_function(
env: napi_env,
utf8name: cstring,
length: csize_t,
cb: napi_callback,
data: pointer,
res: napi_value
): int {.header:"<node/node_api.h>".}
When I run nim c foo.nim, I get Undefined symbols for architecture x86_64 for symbols in js_native_api.h (eg: napi_create_function), but the symbols in node_api.h are found by the linker. Remember that node_api.h includes js_native_api.h (as seen here).
Undefined symbols for architecture x86_64:
"_napi_create_function", referenced from:
_createFn__NEWhgHCwqbksHULYRnxXfA in #m..#s..#s..#s.nimble#spkgs#snapibindings-0.1.0#snapibindings.nim.c.o
The root problem likely isn't related to Nim, but I don't know how to use clang to check if the problem is reproducible without Nim.
So my question is:
How do I get the linker to find the missing symbols?
Versions
nim v1.4.8
clang v12.0.0
x86_64-apple-darwin19.6.0
nodejs v14.13.1 (installed with Homebrew into /usr/local/Cellar/node/14.13.1)
nim c
/Users/alec/.nimble/bin/nim
c
--colors:on
--noNimblePath
-d:NimblePkgVersion=0.1.0
--path:/Users/alec/.nimble/pkgs/nimdbx-0.4.1
--path:/Users/alec/.nimble/pkgs/nimterop-0.6.13
--path:/Users/alec/.nimble/pkgs/regex-0.19.0
--path:/Users/alec/.nimble/pkgs/unicodedb-0.9.0
--path:/Users/alec/.nimble/pkgs/cligen-1.5.4
--path:/Users/alec/.nimble/pkgs/cbor-0.6.0
--path:/Users/alec/.nimble/pkgs/napibindings-0.1.0
--path:'/Users/alec/.nimble/pkgs/docopt-#master'
--path:/Users/alec/.nimble/pkgs/regex-0.19.0
--path:/Users/alec/.nimble/pkgs/unicodedb-0.9.0
--hints:off
-o:/Users/alec/my-project/dist/foo
/Users/alec/my-project/foo.nim
clang
clang
-o
/Users/alec/my-project/foo
/Users/alec/.cache/nim/foo_d/stdlib_assertions.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_dollars.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_formatfloat.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_io.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_system.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snapibindings-0.1.0#snapibindings#sutils.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snapibindings-0.1.0#snapibindings.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_parseutils.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_math.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_unicode.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_strutils.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_posix.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_options.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_times.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_os.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_hashes.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_tables.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimterop-0.6.13#snimterop#sglobals.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_streams.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_lexbase.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_parsejson.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_json.nim.c.o
/Users/alec/.cache/nim/foo_d/stdlib_cpuinfo.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sprivate#slibmdbx.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sprivate#svals.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sError.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sDatabase.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sData.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sCollection.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sTransaction.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#snimdbx-0.4.1#snimdbx#sCRUD.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sdata.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sdata#sfrom_json.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sdata#sto_json.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#squery.nim.c.o
/Users/alec/.cache/nim/foo_d/#m..#s..#s..#s.nimble#spkgs#scbor-0.6.0#scbor.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sdata#sfrom_cbor.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sdata#sto_cbor.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sref.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#squery#sdocument.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#sfunctions.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoopkg#seval.nim.c.o
/Users/alec/.cache/nim/foo_d/#mfoo.nim.c.o
-lm
/Users/alec/.nimble/pkgs/nimdbx-0.4.1/libmdbx-dist/libmdbx.a
-ldl

So my question is:
How do I get the linker to find the missing symbols?
make sure you are actually linking a library (statically or dynamically) which holds symbols you need. (please show how you link it.)
make sure your library actually HAS correct symbols (open file with hex editor and search for symbols)
make sure this library is of correct architecture. there are tools that let you check this. (on Windows it's dumpbin /headers file)
make sure you are importing it correctly. (i see only {.header.} pragma but others needed pragmas are absent). please show more code and command lines. so we can investigate further.

Related

When linking a shared library on linux, are all modules included?

I'm porting a system of apps from AIX to linux, and all of those apps include a single shared library. I've got the shared library building on as a linux .so now - and I see at least one post here that describes how to specify what's exported from a shared library (as AIX does via a .exp file).
Just one silly question, though. On AIX, if a module in a shared library is not referenced by anything in the app that's linking to it, it is ignored by the linker. That doesn't seem to be the case on linux - but I want to make sure.
While testing my linux shared library, I left out one module with dependencies I wasn't ready to deal with yet (or more accurately, I provided a substitute module with dummy functions for all the entry points to that module, thinking that would allow it to link). So far, so good. But when I attempted to link that shared library into a trivial test app, the linker reported unresolved symbols for stuff referenced by another shared library module that is itself only referenced from within the module I replaced with dummies. I.e., I would have expeceted that module to simply be ignored...
In other words, this module is being considered by the linker as part of the final application even though nothing in the app references it. I tried the same experiment on AIX (replacing the same module with dummies and attempting to link a trivial app there). No complaints.
So, The AIX linker only attempts to resolve shared library module dependencies if those modules themselves are explicitly called in from the application. But the linux linker attempts to resolve dependencies for all shared library modules whether they're called in from the application or not.
Is this true? And if so, is there any way to override that behavior? Ultimately, when I port everything, all of the dependencies will resolve. But for now, it's hard to leave something out - even if it's not referenced...
Here's a minimal case:
main.c contains function main(), which calls function one().
one.c contains function one(), which does nothing.
two.c contains function two(), which calls function three().
There is no function three(), but libshared.so is built from
modules one.c and two.c. Program main is built from main.c and
links in libshared.so.
The linker needs to resolve function one(), which is in the shared
library. But that's all main.c requires. Still, function two() in
the library references function three(), which doesn't exist.
The linker will complain about the undefined symbol 'three', even
though program main doesn't need it.
On AIX the linker will not complain and everything will work.
main.c:
#include <stdio.h>
int one();
int main()
{
one();
}
one.c:
#include <stdio.h>
int one()
{
return 1;
}
two.c:
#include <stdio.h>
int three();
int two()
{
return three();
}
build libshared.so with modules one.c and two.c:
gcc -fPIC -shared one.c two.c -o libshared.so
Attempt to build main from main.c and libshared.so:
gcc main.c -o main -L. -lshared
./libshared.so: undefined reference to `three'
collect2: error: ld returned 1 exit status
The linker reports an undefined reference to 'three',
which is referenced from two() - but main() doesn't ever call two().
The actual answer: shared libraries are in fact shared objects: they are treated as a single object, not as a *.a library.
This shows that Linux (meaning: glibc/gcc/gold/ld) and AIX have different concepts regarding shared objects.
In Linux, when you link an executable, ld/gold checks the dependencies of the used shared objects as well -- Aix linker doesn't: it assumes that the shared objects are to be used as they are, their dependencies aren't part of the current linking. (At least this is the default behaviour.)
Here is a summary of my tests:
+----------------+--------------------+-------------------------------+
| | AIX | linux |
+----------------+--------------------+-------------------------------+
| libshared.so | only with option | yes |
| can be created | -Wl,-berok | |
+----------------+--------------------+-------------------------------+
| main | yes | only with option |
| can be created | | -Wl,--allow-shlib-undefined |
+----------------+--------------------+-------------------------------+
Note: My random thoughts regarding AIX and linking: http://lzsiga.users.sourceforge.net/aix-linking.html
By default the GNU binutils linker, ld on
Linux requires a symbol ref to be defined by some input file (i.e. object file or
shared library) in the linkage if ref is referenced by the definition of any
symbol def in any input file that the linkage needs. It doesn't matter whether def is referenced in turn.
Your program linkage needs libshared.so. libshared.so defines two, which refers to three,
so three must be defined.
You can countermand this default behaviour to tolerate undefined references in shared libraries
(but not in object files) as follows:
$ gcc main.c -o main -L. -lshared -Wl,--allow-shlib-undefined
--allow-shlib-undefined is documented in the ld manual
The notion of module in your language corresponds to translation unit at the
compilation level and object file at the linkage level. It might be helpful to
appreciate that an object file input to the linkage of a ELF program or shared library
has no distinct existence in the program or shared library. It is cut into
pieces and scattered around. So there is no sense in which it would be possible
for a linkage:
$ gcc main.c -o main -L. -lshared ...
to ignore the unreferenced module two.(c|o) within
libshared.so. There is no such thing. If that linkage did not need any
definition provided by libshared.so then it would ignore the shared library
altogether1. If it needs the shared library, then by default its references
must be resolved.
[1] That is, on Debian-clan systems where gcc is built to invoke ld with the --as-needed option
by default. On Redhat-clan systems GCC by default links shared libraries if they are input, needed or not.

How do I invoke the “--enable-stdcall-fixup” option?

While building a DLL under Windows I get the following output:
Linking main.exe ...
Warning: resolving _findPeaksWrapper by linking to _findPeaksWrapper#16
Use --enable-stdcall-fixup to disable these warnings
Creating library file: HSdll.dll.a
Use --disable-stdcall-fixup to disable these fixups
It’s not clear to me where I should be placing the --enable-stdcall-fixup flag. Putting it into the ghc-options field of my .cabal file gives a GHC error, while putting it into cc-options or ld-options seems not to do anything (the warnings are still displayed). Where should this flag go?
Googling indicates that --enable-stdcall-fixup is an option to ld. There are a few different pathways by which cabal's final link step can happen, but in your case it is apparently
Cabal -> ghc (link step) -> gcc -> ld
so to match this you must specify
ghc-options: -optl-Wl,--enable-stdcall-fixup

Symbols not found during linking

I have a problem with a shared library (Linux) and a program that links against this library but does not find the symbols - although they are there. That's what I have:
A shared library "libetest.so" that is located in /usr/lib. When I do an
readelf -Ws /usr/lib/libetest.so.0
it gives (beside some others) this output:
54: 000052c0 905 FUNC LOCAL DEFAULT 11 ETEST_open_connection
Now I have an application that makes use of ETEST_open_connection(). When I build it with
gcc lib_test.cpp -DENV_LINUX -letest
it fails with a linker error
lib_test.cpp:(.text+0x32): undefined reference to `ETEST_open_connection'
As shown before the symbol is there! Any idea why this fails?
Please try:
gcc -DENV_LINUX -letest lib_test.cpp
This should be the correct argument order.

crt1.o: In function `_start': - undefined reference to `main' in Linux

I am porting an application from Solaris to Linux
The object files which are linked do not have a main() defined. But compilation and linking is done properly in Solaris and executable is generated. In Linux I get this error
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
My problem is, I cannot include new .c/.o files since its a huge application and has been running for years. How can I get rid of this error?
Code extractes of makefile:
RPCAPPN = api
LINK = cc
$(RPCAPPN)_server: $(RPCAPIOBJ)
$(LINK) -g $(RPCAPIOBJ) -o $(RPCAPPN)_server $(IDALIBS) $(LIBS) $(ORALIBS) $(COMMONLIB) $(LIBAPI) $(CCLIB) $(THREADLIB) $(DBSERVERLIB) $(ENCLIB)
Try adding -nostartfiles to your linker options, i.e.
$(LINK) -nostartfiles -g ...
From the gcc documentation:
-nostartfiles
Do not use the standard system startup files when linking. The standard system libraries are used normally, unless -nostdlib or -nodefaultlibs is used.
This causes crt1.o not to be linked (it's normally linked by default) - normally only used when you implement your own _start code.
-shared link option must be used when you compile a .so
The issue for me was, I by mistake put int main() in a namespace. Make sure don't do that otherwise you will get this annoying link error.
Hope this helps anyone :)
I had similar result when trying to build a new test project with boost, and it turned out that I was missing one declaration :
#define BOOST_TEST_MODULE <yourtestName>
I had this same problem when creating my c project, and I forgot to save my main.c file, so there was no main function.
I had a similar result when compiling a Fortran program that had C++ components linked in. In my case, CMake failed to detect that Fortran should be used for the final linking. The messages returned by make then ended with
[100%] Linking CXX executable myprogram
/lib/../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
make[3]: *** [myprogram] Error 1
make[2]: *** [CMakeFiles/myprogram.dir/all] Error 2
make[1]: *** [CMakeFiles/myprogram.dir/rule] Error 2
make: *** [myprogram] Error 2
The solution was to add
set_target_properties(myprogram PROPERTIES LINKER_LANGUAGE Fortran)
to the CMakeLists.txt, so that make prints out:
[100%] Linking Fortran executable myprogram
[100%] Built target myprogram
I had the same issue with a large CMake project, after I moved some functions from one code file to another. I deleted the build folder, recreated it and rebuilt. Then it worked.
Generally, with suddenly appearing linker errors, try completely deleting your build folder and rebuilding first. That can save you the headaches from trying to hunt down an error that actually simply shouldn't be there: There might be CMake cache variables floating around that have the wrong values, or something was renamed and not deleted, ...
I had the same issue as to OP but on on FreeBSD 13.1.
What solved the issue was simply adding:
int main()
{
}
Since the .cpp file was only an object file containing definitions and declarations using:
extern "C"
{
<all definitions and declarations code goes here>
}
Every time I tried compiling this, the compiler kept throwing the same error as to OP.
So all I did was add an empty main() function all the way at the bottom and code compiled with no errors.

Installing and Linking PhysX Libraries in Debian Linux

I am trying to get PhysX working using Ubuntu.
First, I downloaded the SDK here:
http://developer.download.nvidia.com/PhysX/2.8.1/PhysX_2.8.1_SDK_CoreLinux_deb.tar.gz
Next, I extracted the files and installed each package with:
dpkg -i filename.deb
This gives me the following files located in /usr/lib/PhysX/v2.8.1:
libNxCharacter.so
libNxCooking.so
libPhysXCore.so
libNxCharacter.so.1
libNxCooking.so.1
libPhysXCore.so.1
Next, I created symbolic links to /usr/lib:
sudo ln -s /usr/lib/PhysX/v2.8.1/libNxCharacter.so.1 /usr/lib/libNxCharacter.so.1
sudo ln -s /usr/lib/PhysX/v2.8.1/libNxCooking.so.1 /usr/lib/libNxCooking.so.1
sudo ln -s /usr/lib/PhysX/v2.8.1/libPhysXCore.so.1 /usr/lib/libPhysXCore.so.1
Now, using Eclipse, I have specified the following libraries (-l):
libNxCharacter.so.1
libNxCooking.so.1
libPhysXCore.so.1
And the following search paths just in case (-L):
/usr/lib/PhysX/v2.8.1
/usr/lib
Also, as Gerald Kaszuba suggested, I added the following include paths (-I):
/usr/lib/PhysX/v2.8.1
/usr/lib
Then, I attempted to compile the following code:
#include "NxPhysics.h"
NxPhysicsSDK* gPhysicsSDK = NULL;
NxScene* gScene = NULL;
NxVec3 gDefaultGravity(0,-9.8,0);
void InitNx()
{
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
if (!gPhysicsSDK)
{
std::cout<<"Error"<<std::endl;
return;
}
NxSceneDesc sceneDesc;
sceneDesc.gravity = gDefaultGravity;
gScene = gPhysicsSDK->createScene(sceneDesc);
}
int main(int arc, char** argv)
{
InitNx();
return 0;
}
The first error I get is:
NxPhysics.h: No such file or directory
Which tells me that the project is obviously not linking properly. Can anyone tell me what I have done wrong, or what else I need to do to get my project to compile? I am using the GCC C++ Compiler. Thanks in advance!
It looks like you're confusing header files with library files. NxPhysics.h is a source code header file. Header files are needed when compiling source code (not when linking). It's probably located in a place like /usr/include or /usr/include/PhysX/v2.8.1, or similar. Find the real location of this file and make sure you use the -I option to tell the compiler where it is, as Gerald Kaszuba suggests.
The libraries are needed when linking the compiled object files (and not when compiling). You'll need to deal with this later with the -L and -l options.
Note: depending on how you invoke gcc, you can have it do compiling and then linking with a single invocation, but behind the scenes it still does a compile step then a link step.
EDIT: Extra explanation added...
When building a binary using a C/C++ compiler, the compiler reads the source code (.c or .cpp files). While reading it, there are frequently #include statements that are used to read .h files. The #include statements give the names of files that must be loaded. Those exact files must exist in the include path. In your case, a file with the exact name "NxPhysics.h" must be found somewhere in the include path. Typically, /usr/include is in the path by default, and so is the current directory. If the headers are somewhere else such as a subdirectory of /usr/include, then you always need to explicitly tell the compiler where to look using the -I command-line switches (or sometimes with environment variables or other system configuration methods).
A .h header file typically includes data structure declarations, inline function definitions, function and class declarations, and #define macros. When the compilation is done, a .o object file is created. The compiler does not know about .so or .a libraries and cannot use them in any way, other than to embed a little bit of helper information for the linker. Note that the compiler also embeds some "header" information in the object files. I put "header" in quotes because the information only roughly corresponds to what may or may not be found in the .h files. It includes a binary representation of all exported declarations. No macros are found there. I believe that inline functions are omitted as well (though I could be wrong there).
Once all of the .o files exist, it is time for another program to take over: the linker. The linker knows nothing of source code files or .h header files. It only cares about binary libraries and object files. You give it a collection of libraries and object files. In their "headers" they list what things (data types, functions, etc.) they define and what things they need someone else to define. The linker then matches up requests for definitions from one module with actual definitions for other modules. It checks to make sure there aren't multiple conflicting definitions, and if building an executable, it makes sure that all requests for definitions are fulfilled.
There are some notable caveats to the above description. First, it is possible to call gcc once and get it to do both compiling and linking, e.g.
gcc hello.c -o hello
will first compile hello.c to memory or to a temporary file, then it will link against the standard libraries and write out the hello executable. Even though it's only one call to gcc, both steps are still being performed sequentially, as a convenience to you. I'll skip describing some of the details of dynamic libraries for now.
If you're a Java programmer, then some of the above might be a little confusing. I believe that .net works like Java, so the following discussion should apply to C# and the other .net languages. Java is syntactically a much simpler language than C and C++. It lacks macros and it lacks true templates (generics are a very weak form of templates). Because of this, Java skips the need for separate declaration (.h) and definition (.c) files. It is also able to embed all the relevant information in the object file (.class for Java). This makes it so that both the compiler and the linker can use the .class files directly.
The problem was indeed with my include paths. Here is the relevant command:
g++ -I/usr/include/PhysX/v2.8.1/SDKs/PhysXLoader/include -I/usr/include -I/usr/include/PhysX/v2.8.1/LowLevel/API/include -I/usr/include/PhysX/v2.8.1/LowLevel/hlcommon/include -I/usr/include/PhysX/v2.8.1/SDKs/Foundation/include -I/usr/include/PhysX/v2.8.1/SDKs/Cooking/include -I/usr/include/PhysX/v2.8.1/SDKs/NxCharacter/include -I/usr/include/PhysX/v2.8.1/SDKs/Physics/include -O0 -g3 -DNX_DISABLE_FLUIDS -DLINUX -Wall -c -fmessage-length=0 -MMD -MP -MF"main.d" -MT"main.d" -o"main.o" "../main.cpp"
Also, for the linker, only "PhysXLoader" was needed (same as Windows). Thus, I have:
g++ -o"PhysXSetupTest" ./main.o -lglut -lPhysXLoader
While installing I got the following error
*
dpkg: dependency problems prevent configuration of libphysx-dev-2.8.1:
libphysx-dev-2.8.1 depends on libphysx-2.8.1 (= 2.8.1-4); however:
Package libphysx-2.8.1 is not configured yet.
dpkg: error processing libphysx-dev-2.8.1 (--install):
dependency problems - leaving unconfigured
Errors were encountered while processing:
*
So I reinstalled *libphysx-2.8.1_4_i386.deb*
sudo dpkg -i libphysx-2.8.1_4_i386.deb

Resources