How to avoid system standard C/C++ library on linux? - c++

I installed a new version of GCC, which is sort contaminate my linux system. I plan to handle multiple versions of GCC in a better way. I plan to have all different versions installed under /opt/tools directory. And then my project makefile explicitly specifies the version to use. That includes all the binary executable, i.e. g++, gcc etc., and header files, libraries...
The benefit of this approach is clear. The build is more reproducible. It does not assume the version but pick the very specific one. Switching between different compiler versions all happens inside makefile.
To achieve that I use "-nostdinc" and put all include path explicitly into my compile command line. My code includes limits.h and it causes weird build error.
limits.h is part of libc6-dev installed in my debian. But it's not in gcc's include directory. Some online material says standard C lib is part of OS. My question is that is it practical to build code independent of system header files and libraries? I doubt there might be other headers are missing from gcc. Originally, I thought gcc comes with everything. It's not the case?
In other words, do system libraries and headers depends on specific GCC version that comes with the debian distribution? I kind of feeling uncomfortable that system headers and libs are from let's say GCC 4.7, and I am using GCC 5.3.

There're a few layers in a typical Linux/"free unix" system relevant to program compilation.
Kernel. User-level programs rarely interact with kernel directly, although they can.
Kernel-specific headers, used by kernel modules and bound to a particular build of Linux kernel. In a Debian these headers come in linux-headers-<kernel-version>. There could be multiple packages dedicated to corresponding kernel versions. You don't need them unless your program is a kernel-module or alike.
Kernel-specific parts of libc. In a Debian system this comes in package linux-libc-dev. Usually this package isn't specific to a particular kernel version, but rather to a "generation of versions" (it evolves slowly and reflects appearance of new kernel user-level facilities, constants etc). You do need this package to compile a typical complex user-land program, because it contains important system-wide constants, and types definition
libc. This library provides all usual "C library" functions, facilities etc, sometimes it wraps corresponding kernel facilities (think of open(), send(), brk() functions), sometimes it provides its own high-level features (e.g. qsort() implementation). You do need the library to build virtually any program. In a debian system it comes in several packages, headers are in libc6-dev. There could be multiple different libc instances running on top of a single Linux kernel at once (e.g. in chroots), but since the library depends on certain file hierarchy, typically there's only one.
Compilers. Compilers come with their own sets of headers, but for a C-compiler there're much less compiler-specific headers than, for example, for a C++-compiler, because typically C++ compilers have their own STL implementation which is a header-library by language design. Most of these .h headers in C compiler are responsible for various compiler-specific tricks like varargs handling (stdarg.h) or Cilk stuff. For example, in gcc-4.7 package in Debian 7 there're only 47 .h files, most of them being a part of libgcc
Actually, in Debian you can have any number of compilers installed and they won't interfere with each other. For example, right now in my Ubuntu-16.04 there're 4 gcc versions instantly available for installation: 4.7.4, 4.8.5, 4.9.3, 5.3.1, — and 4 clang versions: 3.5, 3.6, 3.7 and 3.8. All these compilers of different versions can be installed with apt-get install <package-name>. I guess that a modern Debian has more or less the same set. Using relatively simple rules you can build a package for any given compiler and any given version.
A required C compiler may be chosen during compilation with CC environment variable and one doesn't need to change Makefile for that.
You may need -nostdinc only if you plan to use a completely different libc implementation, which usually is not a case. But sometimes it's useful, e.g. for building programs for initrd or other stages of system boot-up when there's no a "complete environment".

GCC doesn't ship any C header files. The GNU C library or glibc for short is a separate project. It doesn't really make sense to have a libc agnostic toolchain as GCC needs a C library and it has nothing to do with the version of the GCC compiler. No, you don't need a VM or "Linux From Scratch", which is ill-suited because it tells you to compile the entire toolchain from source. It's really dead simple to install different versions of GCC to their own prefix (destination folder). It even allows you to add prefixes to the name of the executable to make things easier.
I seriously recommend you dive into Installing GCC. It's written by an actual GCC maintainer, and it's straight to the point. Don't make it harder than it is.
To compile GCC, do:
tar xzf gcc-VERSION.tar.gz
cd gcc-VERSION
./contrib/download_prerequisites
cd ..
mkdir objdir
cd objdir
$PWD/../gcc-VERSION/configure --prefix=$HOME/gcc-VERSION --enable-languages=c,c++
make
make install
And the option I was talking about from the manual:
--program-prefix=prefix
- GCC supports some transformations of the names of its programs when installing them. This option prepends prefix to the names of programs
to install in bindir (see above). For example, specifying
--program-prefix=foo- would result in gcc being installed as
/usr/local/bin/foo-gcc.
Here /usr/local is just the default prefix for autotools. I strongly do not recommend you install GCC there. Do this for each version, and you can have gcc-4.8, gcc-5.3, etc.

Related

Use Multiple Versions of GCC During Compilation & Dependency on GCC in Object File Execution

This may be a dumb question, but I am a novice in the compilation of a C or C++ project through the command line. I am currently trying to cross-compile some frameworks to run in an aarch64 device, which has a built-in gcc5.4.0. However, some of the libraries require at least gcc7.5.0. So my first question is:
Can a framework that is compiled with gcc7.5.0 version can be used in an environment where gcc5.4.0 is present?
Moreover, some processes the I try to run on the device also requires gcc7.5.0. Therefore, my second question is that:
Can an object file (.o, e.g. the output of the compiled .c / .cpp file) that is compiled with gcc7.5.0 run on a system with gcc5.4.0?
Lastly, some processes require the libraries compiled in gcc5.4.0 and gcc7.5.0 to be used together. Therefore, I have to link the .so files that are generated by both gcc5.4.0 and gcc7.5.0. Hence, my last question is:
Can one create an executable by using libraries together that are compiled with different gcc versions?
Thanks.
For your first two questions: the presence or absence of a compiler in the system does not matter. I've run software on machines where no compiler was installed (it was compiled elsewhere). I've run software on machines where a bunch of compilers are installed, included multiple version of g++.
For your last question: the thing which matter when linking (either statically, at link time, or dynamically at execution time) libraries is called ABI. There are two aspects of the ABI: for the language itself, and for the standard libraries. For both, GCC maintains forward compatibility: using the latest compiler and standard library, you can link with object files compiled with older compiler (and for older standard library) since something like 3.4. In some more restricted cases (less well documented), you can even use the older compiler and standard library.
If you want to execute a program dynamically linked (which is usually the default with GCC) with a newer version of the standard library than the one on your system, you need to ensure it is found. That's a whole other subject, but here are two key words to help you find information for Unix (I know nothing about how Windows handle this, I presume but could be wrong that MacOS is a unix for this purpose): LD_LIBRARY_PATH and rpath.
Obviously meeting bugs is always a possibility and some care is needed in some cases. So here are some relevant links with the details.
GCC Compiler option related to ABI.
Standard library documentation related to ABI.
On the use on the C++11 library ABI. C++11 put additional requirements on some types (notably std::string) which prevented GCC to keep its old ABI for those types. Thus a new ABI was introduced in GCC 5 or so and if you want to be compatible with the previous one you have to pay attention. (Note that distributers sometimes forced the old ABI even with GCC version 5 and later)
Older related SO question

How to set up a C++ toolchain for cross-compilation?

I have a target system Astra Linux Smolensk, which has access to very outdated packages with GCC 6 among them. It does not support C++17, which is required for some very useful 3rd party libraries and language features. At some point I am considering a possibility of using concepts from 20 standard. But there is no easy way to achieve that.
Basically, I see 2 ways:
Compile needed version of GCC by myself and have a custom version of Astra Linux for building with additional packages (which is not a good option since we have restrictions for system modification). I am about to try out this option, but it is not the subject of this question.
Cross-compile with latest GCC on Ubuntu using a toolchain.
So, what do I need in order to create a toolchain for a custom version of Linux? The only thing I am sure of is the Linux Core version. Can I use an existing Linux toolchain or do I have to export system libraries and create a custom toolchain?
Here I found out some tools that seem to be helpful. For instance:
Buildroot
Buildroot is a complete build system based on the Linux kernel configuration system and supports a wide range of target architectures. It generates root file system images ready to be written to flash. In addition to having a huge number of packages which can be compiled into the image, it also generates a cross toolchain to build those packages from source. Even if you don't want to use buildroot for your root filesystem, it is a useful tool for generating a toolchain. Buildroot supports uClibc-ng, glibc and musl.
I wonder if it does what I need and can I use a latest GCC compiler with those generated toolchains.
I found similar questions:
How to build C++17 application in old linux distro with old stdlib and libc?
https://askubuntu.com/questions/162465/are-gcc-versions-tied-to-kernel-versions
How can I link to a specific glibc version?
Some clarification is needed:
The project relies heavily on a lot of 3rd party dependencies from the target linux's package repository. Moreover, I use dynamic .so modules that may be loaded both implicitly and explicitly.
Today with docker and modern CI/CD pipelines based on container, we don't rely on process compile very often as old days.
With the help of musl, we can even create universal Linux binaries with static linkage: We use all static libraries rather than dynamic libraries. Then we ship one executable file.
According to musl's doc, it needs
Linux kernel >=2.6.39
This is a very old version released around 2011, so even old Linux distro's can run our binaries.
Musl is widely used in many projects, especially in Rust projects, we provide Musl builds for users as conveniences.
Note that we may need to fix our codebase when using Musl, there are very slight differences with GNU libc, which we should be aware.

How does musl's GCC wrapper differ from musl's cross-compiler?

I am trying to compile various programs such as MariaDB with a musl toolchain. That is, I don't want any dependencies on glibc or GNU's linker after compilation has finished.
Thus far, I have been using musl's GCC wrapper, musl-gcc to compile things. But, with larger programs like MariaDB I struggle to get all the necessary libraries and headers and symlinking or adding environment variables for the compilation doesn't really help.
I see mention of building a cross-compiler targeting musl libc with additional documentation and code at this GitHub repo. From the documentation on the cross-compiler:
This gives you a full, relocatable musl-targeting toolchain, with C++ support and its own library paths you can install third-party libraries into.
It sounds like this could help me, but I am not sure how this is very different from musl's GCC wrapper, which as I understand, just alters where GCC looks for libraries and headers etc.
Ultimately, I am unsure how different this cross-compiler really is from the GCC wrapper and if it would be useful in my case. Why would I need my own library paths to install third-party libraries into when I can just symlink to existing libraries and use the GCC wrapper? Is the cross-compiler the way I should be compiling things, especially bigger code bases?
All the wrapper does is remove the default library and include paths and add replacement ones. Otherwise, it relies on the compiler's view of the ABI being sufficiently matched that a GCC that thinks it's targeting glibc (*-linux-gnu) works with a musl (*-linux-musl) target.
A full GCC toolchain has a number of "target libraries" - libraries that are linked into the output program to provide some functionality the compiler offers. This includes libgcc (software multiply or divide, software floating point, etc. according to whether the target arch needs these things, and unwinding support for exception handling), libstd++ (the C++ standard library), and a number of other things like libgomp (GNU OpenMP runtime implementation for use with #pragma OMP ...). In theory all of these possibly depend on the specific target ABI, including the libc, and potentially link to symbols from libc. In practice, for the most part libgcc doesn't, and is "safely" reusable with a different libc as long as the basic type definitions and a few other ABI things match.
For the other libraries with more complex dependencies on libc, it's generally not expected that a build against one libc would work with a different one. musl libc provides some degree of ABI-compat for using glibc-linked libraries, so there's some hope that they'd work anyway, but you'd need to copy them to the new library path. However, GCC's C++ standard library headers also seem to have some heavy dependency on the (libc) system headers for the target, and when setup for glibc do not seem to work with musl. There is probably some way to make this work (i.e. to add C++ support to the wrapper), but it's an open problem exactly how to do it.
Even if this could be made to work, though, the deeper you go, the more reasons you're likely to find that you'd rather just have a proper cross-compiler toolchain that knows it's targeting musl. And nowadays these are easy enough to build. But if you find you're needing additonal third party libraries too, and don't want to build them yourself, it probably makes more sense to just use a Docker image (or other container) with a distro that provides library binaries for you.

what is the difference between lib-mingw and lib-vc2019

I'm new to Windows programming and found that lots of prebuilt libraries for Windows offer libraries like lib-mingw, lib-vc2019, lib-vc2017...
Could anyone help to point out
what is the difference? Which library should I use in what case?
If I want to use Clang on Windows, which one should I use?
Why these different libraries rarely seen on Linux (let's say
Ubuntu), does package managers like apt hide this detail? In other word, why there's no such thing like lib-gcc.a, lib-clang.a on Linux platform?
Mingw (GCC), VC2019 and VC2017 are different compilers. Use the library corresponding to your compiler.
I'm not sure but I think none of them will work with Clang. At least on Linux GCC and Clang are very similar. I mean they are mostly binary compatible, many same compiler flags, many same compiler extensions. Clang tried to make it possible to easily replace GCC in your build pipeline. But all these information is for Linux.
These libraries are not seen on Linux because all these compilers are Windows compilers
You can always build a library with your compiler to use it in your project with your compiler (if you have the sources).
If it's a third party closed source library and you are a paying customer you can ask if they build it for you. It's usually better the add a new compiler to the build pipeline than to lose a customer.

How to install Clang from the binary distribution?

Clang has a binary distro, of sorts, but there isn't any README file or anything to tell you what's in the tarball or what to do with it.
It appears that I need to separately download and install libc++. I may need to copy only the clang binary and maybe a few others, but not all the llvm-* stuff. This is just judging by the lack of any C++ headers in the binary distro (although some environment-specific headers are included), and the lack of llvm-as and such on my existing LLVM 3.2 installation from Xcode.
I just want to run the compiler, not develop with libclang or assemble LLVM assembly files. Is there an instruction page somewhere?
The LLVM project doesn't actually expect many people to use the binary distribution they put out. LLVM does releases for the periodic validation, but it's expected that most users will get LLVM through their OS distro or will build the version they want from source.
See this email thread where clang developers are discussing how the binaries distrbution is used.
That said, you can use their distribution if you want. What to install depends on what you want to do:
Use clang as a static compiler.
Build clang based tools.
Use LLVM as a backend for your custom language compiler.
I may need to copy only the clang binary and maybe a few others, but not all the llvm-* stuff.
If all you want to do is compile C/C++/Obj-C, then I believe all you need is the clang binary (and the 'clang++' symbolic link), the 'built-in' headers, and the runtime libraries. You'll find those headers and libs in /lib/clang/<version>/. (The clang compiler typically finds its built-in parts by their location relative to the binary.)
If you want to use LLVM as a backend, you'll need either the LLVM headers and libraries to build and link against, or you'll need some of the ll* binaries to process output of your frontend.
If you want to build clang based tools you'll need the clang headers and libraries to build and link against, either the stable C API or the unstable C++ API.
Note that the libraries are built with RTTI and exceptions disabled. This changes the ABI and so you can't link these with code built with RTTI or exceptions enabled.
It appears that I need to separately download and install libc++.
Correct, libc++ is not included as part of LLVM's distribution. Many of the nominal LLVM subprojects aren't included. LLDB is another example.
Nor does LLVM include a standard C library or the basic Objective-C frameworks.
For Ubuntu/Debian (incuding Linux Mint) based Linux distributions, there are also pre-built .deb files from http://llvm.org/apt/
This has the advantage that it is easer to uninstall at a later point, and also provides Clang 3.4 nightly builds (the 3.3 version is also provided). Simply add one line to your sources.list (or use a GUI package manager to do so) and you're set.