Fully static libcurl build - linux

I am building a program (on linux) which relies on libcurl. I'd prefer that it could be distributed and run without needing any external dependencies. libcurl seems to have quite a few of these... hence, I would like to know if there is any way to statically compile libcurl so as to include all of its dependencies?
Or, do any pre-built versions of it already exist?

Related

Meson build: How to use compiled library instead of downloading it as subproject and build

I am trying to build gstreamer using gst-build: https://gitlab.freedesktop.org/gstreamer/gst-build
Glib is one of the subprojects it is downloading and compile. But I am thinking of replacing it with the previously compiled version. How should I do it in the cross-file? Or there is no way other than hacking meson.build
Thanks
Regrds
It depends on the discovery methods that dependency supports, if it uses pkg-config, it's probably as easy as setting [built-in options]:pkg_config_path in your cross file (or the various $PKG_CONFIG_PATH environment variables) to include the pkg-config file. I'm pretty sure that glib uses pkg-config.

Build and bind against older libc version

I have dependencies in my code that requires libc. When building (cargo build --release) on Ubuntu 20.04 (glibc 2.31) the resulting executable doesn't run on CentOS 7 (glibc 2.17). It throws an error saying it requires GLIBC 2.18.
When build the same code on CentOS 7 the resulting executable runs on CentOS 7 and Ubuntu 20.04.
Is there a way to control which GLIBC version is required to build this version on Ubuntu 20.04 too?
If your project does not depend on any native libraries, then probably the easiest way would be to use the x86_64-unknown-linux-musl target.
This target statically links against MUSL Libc rather than dynamically linking against the system's libc. As a result it produces completely static binaries which should run on a wide range of systems.
To install this target:
rustup target add x86_64-unknown-linux-musl
To build your project using this target:
cargo build --target x86_64-unknown-linux-musl
See the edition guide for more details.
If you are using any non-rust libraries it becomes more difficult, because they may be dynamically linked and may in turn depend on the system libc. In that case you would either need to statically link the external libraries (assuming that is even possible, and that the libraries you are using will work with MUSL libc), or make different builds for each platform you want to target.
If you end up having to make different builds for each platform, a docker container would be the easiest way to achieve that.
Try cross.
Install it globally:
cargo install cross
Then build your project with it:
cross build --target x86_64-unknown-linux-gnu --release
cross take the same arguments as cargo but you have to specify a target explicitly. Also, the build directory is always target/{TARGET}/(debug|release), not target/(debug|release)
cross uses docker images prebuilt for different target architectures but nothing stops you from "cross-compiling" against the host architecture. The glibc version in these docker images should be conservative enough. If it isn't, you can always configure cross to use a custom image.
In general, you need to build binaries for a given OS on that OS, or at the very least build on the oldest OS you intend to support.
glibc uses symbol versioning to preserve the behavior of older programs while adding support for new functionality. For example, a newer version of pthread_mutex_lock may support lock elision, while the old one would not. You're seeing this error because when you link against libc, you link against the default version of the symbol if a version isn't explicitly specified, and in at least one case, the version you linked against is from glibc 2.18. Changing this would require recompiling libstd (and the libc crate, if you're using it) with custom changes to pick the old versioned symbols, which is a lot of work for little gain.
If your only dependency is glibc, then it might be sufficient to just compile on CentOS 7. However, if you depend on other libraries, like OpenSSL, then those just aren't compatible across OS versions because their SONAMEs differ, and there's no way around that. So that's why generally you want to build different binaries per OS.

Build static executable on RHEL 7?

I have a C++ project that I'm currently building using dynamic linking to various system libraries. It's on a RHEL 7 system. I've been using devtoolset-9 to get a more modern version of g++ (the system one is 4.8.5, I think). It all works fine, but I'd like to now build a static executable that I will be able to run on a non-RHEL linux system. I've tried specifying -static-libstdc++, but it appears to still be dynamically linked, looking at the ldd output. I've read that devtoolset compilers use some link-time trickery to link in both the system libstdc++ dynamically and any new C++ functionality statically. Is this true? It doesn't work for me; if I copy the executable over to the non-RHEL system and try to run it, I get a bunch of things like this (from memory, so hopefully correct):
/lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found
Is there any way to build a fully static executable using g++ from devtoolset-9? Thank you.

LLVM won't build libLLVM-3.4.so

I'm trying to build llvm 3.4.2 on CentOS 7 with GCC 4.8.5. I can successfully build all of the libs, except libLLVM-3.4.so doesn't want to build - everything else gets created except that one. What's worse is I've managed it previously in the past, but can't do it again now.
I've tried both with CMake and autotools, with the same result. Is there an option I'm missing? Or some error in configuration possibly?
Found it - it was the --enable-shared flag to configure which causes the main shared library to be built. Confusingly this does something completely different from the CMake BUILD_SHARED_LIBS variable, which causes each of the individual libraries to be built as a shared library instead of static, but doesn't build the main shared library.
You can use
LLVM_BUILD_LLVM_DYLIB
when building from source.
The official docs say
BUILD_SHARED_LIBS is only recommended for use by LLVM developers. If you want to build LLVM as a shared library, you should use the LLVM_BUILD_LLVM_DYLIB option.
source: https://llvm.org/docs/CMake.html

how do I solve version conflict that occurs due to multiple version of library inclusion in Linux

In my project, I am trying to use two libraries those are already compiled and generated. Let us say liba.so(our own library created sometime back) and libssl.so.10.(It is available in the Linux).
Now liba.so is having dependency libcurl.so.3 &
libssl.so.10 is having dependency libcurl.so.4 (latest)
Both libcurl.so.3 and libcurl.so.4 are available in the system.
Hence When I try to use both of them in my project, I am getting version conflict. Is it expected? If yes, how do I solve this problem?
Is there any way to modify liba.so dependency with latest libcurl.so.4 without building this library again?
Or do I need to build liba.so again with latest libcurl.so.4?
Thanks for your help
Hence When I try to use both of them in my project, I am getting version conflict. Is it expected? If yes, how do I solve this problem?
There are two solutions.
First, you would carry around the versions of libcurl.so & libssl.so you want to use. You would then use the linker's rpath or LD_LIBRARY_PATH to ensure you load the shared objects you included.
Second, you would build your liba.so to statically link against libcurl and libssl.
If you are working on Android, then number two is your choice. That's because OpenSSL is included on Android, zygote loads it, and you always get the downlevel version 0.9.8 after the fork from zygote.
On Android, you would even need to build a wrapper shared object if all you wanted was a modern OpenSSL like 1.0.1 (that looks a lot like what you are experiencing with libcurl.so.3 and libcurl.so.4).

Resources