using static libcurl.a in C program by minGW64 - c

(I saw answers of every single StOF questions regarding this - none fully helped. I'm very frustrated after trying so hard for 3 days & nights.)
libcurl.a is statically linked with:
OpenSSL 1.1.1k [64bit/32bit]
brotli 1.0.9 [64bit/32bit]
libgsasl 1.10.0 [64bit/32bit]
libidn2 2.3.1 [64bit/32bit]
libssh2 1.9.0 [64bit/32bit]
nghttp2 1.43.0 [64bit/32bit]
zlib 1.2.11 [64bit/32bit]
zstd 1.5.0 [64bit/32bit]
Case 1 - as if curl isn't statically linked
x86_64-w64-mingw32-gcc-10.2.0.exe -o main.exe main.c "C:\curl-7.77.0-win64-mingw\lib\libcurl.a" -DCURL_STATICLIB
Throws unending lines of error, as if libcurl isn't statically linked with its dependencies*:
...\lib\libcurl.a(http2.o):(.text+0x7f): undefined reference to `nghttp2_version'
...\lib\libcurl.a(http2.o):(.text+0x297): undefined reference to `nghttp2_submit_rst_stream'
... (then the errors include many more undefined reference to symbols from nghttp2, ssl, crypt, ssh, gsasl)

The best way to use libcurl is to get the necessary flags via pkg-config. In MSYS2 this works quite well. Otherwise you may need to point the environment variable PKG_CONFIG_PATH to the location of libcurl.pc.
On my system
pkg-config --define-prefix --static --libs libcurl
returns:
-LD:/Prog/winlibs64-11.1.0/custombuilt/lib -lcurl -lidn2 -lrtmp -lssh2 -lnettle
-lgnutls -ladvapi32 -lcrypt32 -lgss -lwldap32 -lzstd -lz -lws2_32 -lrtmp
Note that with MinGW the order of the libraries is also important. The library providing a symbol should be mention on the linker command line after the object that refers to that symbol.
Finally you need to make sure that each library you include was in fact built and used statically. With that I mean no stuff like __declspec(dllexport) may be used when building it, and no __declspec(dllimport) may be used when compiling anything that depends on it. For some libraries this may require specific defines before including the library's header(s).
Specifically for libcurl and nghttp2 I find that it helps to add the following at the top of lib/http2.c and lib/http.c when building libcurl:
#if defined(BUILDING_LIBCURL) && !defined(DLL_EXPORT)
#define NGHTTP2_STATICLIB
#endif
This will define NGHTTP2_STATICLIB when building static libcurl.
I have reported this as a bug at: https://github.com/curl/curl/issues/7353

It is so enormously saddening to see how many people have struggled and are still struggling to statically link libcurl to their program. So much so that a very active Curl maintainer said: "building static is a roller coaster left for the users to deal with on their own as its such a never-ending race for us to try to support."
Since linker is saying undefined references, then libcurl.a must be:
not statically linked
Or, you've got the sequence of libraries unarranged. Linker is sensitive to sequence. Example: If libbrotlidec-static.a needs a function/symbol which is inside libbrotlienc-static.a, then libbrotlienc-static.a must be mentioned before libbrotlidec-static.a
A static library is an archive .a of object .obj files. And they're not statically linked in themselves. That's why, to link some-static-library.a to a program, you need to collect and manually mention every.a single.a static.a library.a that are dependencies of some-static-library.a.
In my Chat#Terminal:~$ project, I should have a make.bat file which shows how to statically link libcurl to a program using gcc or mingw. And finally static-compile the whole program, and ship without any runtime dependency!
On a side-note, curl's precompiled-binary website says: Curl_x.x.x is statically linked with: [list of libraries you provided]. Break your misconception that, the statement made at the website means: Curl.exe is statically linked with the libs, not libcurl.

Related

Removing symbols from `.a`s

I'm compiling a C++ static library using g++ via Cmake. I want to remove symbols relating to the internal implementation so they don't show up in nm. (See here and here for the same with shared libraries.)
This answer tells you how to do it on iOS, and I'm trying to understand what happens under the hood so I can replicate on Linux. They invoke ld with:
-r/--relocatable to Generate relocatable output---i.e., generate an output file that can in turn serve as input to ld.
-x/--discard-all: Delete all local symbols.
AFAICS the -r glues all the modules into one module, and then the -x removes symbols only used inside that module. Is that right?
It's not clear how the linker 'knows' which symbols will be exported externally? Does it rely on __attribute__((visibility("hidden/default"))) as in the .so case?
Edit: clearly I'm confused... I thought cmake invoked ld to link the .os into .a. Googled + clarified above.
Question still stands: how do I modify the build process to exclude most symbols?

Unable to compile a c application that reads smartcard

I am trying to compile an example c application that is using pkcs#11 to finds all
the private keys on the token, and print their label and id, but getting following errors
/tmp/ccAqQ7UI.o: In function initialize':
pkcs11_example1.c:(.text+0x8e5): undefined reference to C_Initialize'
/tmp/ccAqQ7UI.o: In function `get_slot':
The example is taken from here
compilling by using following command;
`gcc pkcs11_example1.c -o slots -L /usr/lib/opensc-pkcs11.so`
I am not sure which library i should link after -L.
Can anyone guide how to compile this and are there some libraries required to link.
C_Initialize and other 60+ functions with "C_" prefix are cryptoki functions defined in PKCS#11 specification. They are usually implemented in standalone library provided by HSM vendor. Looking at your code samples I would say that you need to directly link also PKCS#11 library or you can modify the code to dynamically load PKCS#11 library in runtime with LoadLibrary or dlopen and then acquire pointers to all cryptoki functions via the C_GetFunctionList call. You can also take a look at pkcs11-logger the source code for an example on how to do that.
The link command you give, gcc pkcs11_example1.c -o slots -L /usr/lib/opensc-pkcs11.so, is wrong.
-L takes just path, which is added to paths where libs are searched from, but /usr/lib is default so you don't need this switch at all.
You are missing -l, which takes the library name without lib prefix or .so suffix, so looks like you need -lopensc-pkcs11.
So, first make sure your library file really is /usr/lib/libopensc-pkcs11.so (note lib prefix!) possibly with verion numbers following. Then change build options so link command becomes
gcc pkcs11_example1.c -o slots -lopensc-pkcs11

Linking against a shared library on AIX

I'm trying to link against a shared library (apr) on AIX 5.3 using gcc/libtool.
The output from the compiler is as follows (with some irrelevant flags removed for the sake of simplicity):
libtool: link: gcc -o test test.o -L/opt/freeware/lib -lapr-1 -lpthread -Wl,-blibpath:/opt/freeware lib:/usr/lib:/lib
Then I checked what shared libs the resulting binary uses:
$ ldd test
test needs:
/usr/lib/libc.a(shr.o)
/usr/lib/libpthread.a(shr_xpg5.o)
/unix
/usr/lib/libcrypt.a(shr.o)
/usr/lib/libpthreads.a(shr_comm.o)
Notice that 'libapr-1' is missing here, though the symbols are there in the binary (verified with nm), which suggests that it is linked in statically.
This wouldn't be such a big problem for simple programs. Unfortunately my code in question uses dynamically loadable modules. The main program calls apr_initialize which sets a static variable 'apr_pools_initialized' inside the library. The loadable modules then try to use apr_pool_create which first check whether the initialization has been performed. Since they have their own statically linked apr, the static variable 'apr_pools_initialized' is not at the same memory location what the main program initialized. This makes the statically linked binary non-functional.
The apr library is installed using a precompiled binary rpm (apr and apr-devel). The relevant library files are there:
# rpm -ql apr|grep \\.so$
/opt/freeware/lib/libapr-1.so
/opt/freeware/lib64/libapr-1.so
/usr/lib/libapr-1.so
# rpm -ql apr-devel|grep \\.a$
/opt/freeware/lib/libapr-1.a
/opt/freeware/lib64/libapr-1.a
/usr/lib/libapr-1.a
/usr/lib64/libapr-1.a
/usr/lib64/libapr-1.so
I tried to remove the '.a' files hoping that the linker would have no choice but to use the '.so' and link it dynamically, unfortunately AIX is different and this does not work.
Regarding this topic I have found this answer and another libtool question which give some insight.
The question is: How can I link this to my binary dynamically?
Actually the links referenced contained the solution to this problem, which is:
-Wl,-brtl
Adding these LDFLAGS solved the linking problem.

Statically linking libclang in C code

I'm trying to write a simple syntax checker for C code using the frontend available in libclang. Due to deployment concerns, I need to be able to statically link all the libraries in libclang, and not pass around the .so file that has all the libraries.
I'm building clang/llvm from source, and in llvm/Release+Asserts/lib I have a bunch of .a files that I think I should be able to use, but it never seems to work (the linker spews out thousands of errors about missing symbols). However, when I compile it using the libclang.so also present in that directory as follows:
clang main.c -o bin/dlc -I../llvm/tools/clang/include -L../llvm/Release+Asserts/lib/ -lclang
Everything seems to work well.
What is the minimum set of .a files I need to include to make this work? I've tried including absolutely all of the .a files in the build output directory, with them provided to clang/gcc in different orders, without any success. I only need the functions mentioned in libclang's Index.h, but there don't seem to be any resources or documentation on what the various libclang*.a files are for. It would be very helpful to know which files libclang.so pulls in.
The following is supposed to work, as long the whole project has all static libraries (I counted 116 in my Release/lib directory).
clang main.c -o bin/dlc -I../llvm/tools/clang/include ../llvm/Release/lib/*.a
[edit: clang main.c -o bin/dlc -I../llvm/tools/clang/include ../llvm/Release/lib/libclang.a ../llvm/Release/lib/*.a]
Note that the output binary is not static, so you don't need any -static flag for gcc or ld, if you're using this syntax.
If that doesn't work you might need to list the libraries in order: if some library requires a function available in another library, then it may be necessary to list it first in the command line. See comments about link order at:
http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Link-Options.html#Link-Options

gsoap client compile/link error

Now I am writing a program to call a web service. I write testMain.c. The others are generated by wsdl2h and soapcpp2.
My compiling command is like this:
gcc -Wall -g -c -L. soapC.c soapClient.c stdsoap2.c testMain.c
gcc -o testMain -L/usr/lib -lgsoap -lgsoapck -lgsoapssl soapC.o soapClient.o stdsoap2.o testMain.o
And I get these errors. Please help me.
stdsoap2.o: In function `soap_print_fault':
/test/stdsoap2.c:16279: undefined reference to `soap_check_faultsubcode'
/test/stdsoap2.c:16281: undefined reference to `soap_check_faultdetail'
stdsoap2.o: In function `soap_sprint_fault':
/test/stdsoap2.c:16341: undefined reference to `soap_check_faultdetail'
collect2: ld returned 1 exit status
Recent versions of GCC/ld/the GNU toolchain require that the object and library files be specified in a certain order, so that symbols can be found by the linker in the same order they depend on each other. This means that libraries should go to the end of the command line; your second line (when you're linking) should be
gcc -o testMain -L/usr/lib soapC.o soapClient.o stdsoap2.o testMain.o -lgsoap -lgsoapck -lgsoapssl
instead.
I search the web, and found a post which is very similar with my problem. I use this solution and have solved the problem. http://www.mail-archive.com/gsoap#yahoogroups.com/msg01022.html
You should not need to link stdsoap2.o to your project because it's already included in libgsoap (given through the gcc linker option -lgsoap). Try to exclude stdsoap2.c from your project. From the gSOAP FAQ:
I get a link error with gcc/g++ (GNU GCC). What should I do? For C
apps: use soapcpp2 option -c to generate C code, use only the
package's .c files, link with libgsoap.a (-lgsoap) or use the lib's
source stdsoap2.c (and dom.c when applicable).
I had the same problem with gsoap-2.8.16 compiled from source. (That version was shipped with CentOS 6.)
First I checked for a missing library. According to nm used on all static libraries provided by gsoap-2.8.16:
for X in /usr/local/lib/libgsoap*.a ; do echo $X; nm $X | grep soap_check_faultdetail; done`
it turned out that none of the libraries provided the missing symbols.
A brief look at the source code revealed that the expected return type of both methods soap_check_faultdetail and soap_check_faultsubcode was const char*, and that these were used to generate error messages.
It looked to me as if these are meant to be callbacks that the client must provide. Maybe their implementation is WSDL-dependent and would be supplied by the gsoap code generation utilities - that I don't know, see the answer from #ChristianAmmer above or below.
Anyway, since I knew the symbols were nowhere supplied, and that null-terminated strings were probably acceptable here, I just supplied my own no-op implementation:
// gsoap-missing-symbols.cpp
extern "C" {
const char* soap_check_faultdetail() { return 0; }
const char* soap_check_faultsubcode() { return 0; }
}
This is a brute-force solution. If you follow this solution, you should maybe check for linker warnings in the future; maybe some mechanism (eg. from the gsoap code generator) will supply conflicting implementations later during development.
For later versions of gsoap, I believe these symbols are no longer used and can be dropped (or renamed), see soap_check_faultX in https://www.genivia.com/changelog.html.

Resources