Catching Exceptions in Oracle on Solaris fails - c++

In our code we trying to catch an exception. This code has been working fine for years with different architectures and operating systems (x86, x64, SuSe Linux 11 SP2, Oracle 11g, Oracle 12c). Now we also tried out Solaris 11.3 on x86/64 and Sparc with Oracle 12c.
It turns out that we are not able to catch the exceptions and that the whole program crashes. We produce a shared object library which is then loaded into Oracle and used by a stored procedure. Within that stored procedure we might throw an exception but catch it and make it pretty for Oracle.
The combination of Solaris 11.3/Oracle 12c/x64 now behaves strange:
The extproc process is being killed and Oracle just delivers an ORA-28576: lost RPC connection to external procedure agent error message.
Please find an MVCE at https://gist.github.com/pgab/13ac10f4302d11cab45ba80584eeca0f.
The complete output on Solaris with SQL Developer is:
declare
ret number;
begin
"thrower".test_throw(ret);
end;
Error report -
ORA-28576: lost RPC connection to external procedure agent
ORA-06512: at "thrower.TEST_THROW", line 1
ORA-06512: at line 4
28576. 00000 - "lost RPC connection to external procedure agent"
*Cause: A fatal error occurred in either an RPC network connection,
the extproc agent, or the invoked 3GL after communication had
been established successfully.
*Action: First check the 3GL code you are invoking; the most likely
cause of this error is abnormal termination of the
invoked "C" routine. If this is not the case, check for
network problems. Correct the problem if you find it. If all
components appear to be normal but the problem persists, the
problem could be an internal logic error in the RPC transfer
code. Contact your customer support representative.
Also the used /tmp/debug.log produces just:
about to throw
In comparison the output with SuSe is:
declare
ret number;
begin
"thrower".test_throw(ret);
end;
Error report -
ORA-20001: foo
ORA-06512: at "thrower.TEST_THROW", line 1
ORA-06512: at line 4
And in /tmp/debug.log
about to throw
foo
To be even more confusing:
The same code works perfectly fine on Solaris 11.3 on Sparc,
A single executable is able to throw and catch exceptions properly.
Which bit am I missing here? Maybe it a special linker flag or something else which needs to be activated for Solaris or even for Oracle?
Edit:
With the hint of #Andrew Henle I was digging into compiler and linker versions being used within extproc and the library being produced using strings -a and scanning the output:
On Solaris liboragst contained the following strings (c.f. https://nopaste.xyz/?63251ef69b12e0ac#zgE4Hfagu08eBnSkbIWKcV/Zoux9X6UWw+AH2eGESxM=):
GNU C++ 4.8.2 -m64 -mtune=generic -march=x86-64 -g -fPIC
ld: Software Generation Utilities - Solaris Link Editors: 5.11-1.2458
where as extproc (the process spawned by Oracle RDBMS to load the external procedure) contains this (c.f. https://nopaste.xyz/?913cef4a7fdd4c0d#cHkGRMpWn3IiFwpqv0auys4nn04wfrwtom3eIHEimLE=):
ld: Software Generation Utilities - Solaris Link Editors: 5.11-1.2329
Xa;O;p;F;R=Sun C 5.12 SunOS_i386 Patch 148918-06 2013/06/11;backend;raw;cd;
/opt/SunProd/studio12u3/solarisstudio12.3-148906-08/prod/bin/cc
But there is nothing at /opt/SunProd/studio12u3 being installed.
Furthermore please find below the versions of gcc/g++ and ld:
Solaris:
g++ --version
g++ (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ld --version
ld: Software Generation Utilities - Solaris Link Editors: 5.11-1.2458
2nd Edit:
I have no managed to compile the library with Oracle's developerstudio but still get an ORA-28576 error instead of the wanted ORA-20001. It is a "clean" Solaris 11.3 installation with just Oracle Database, CMake and Developer Studio 12.6.
Cmake issues:
/opt/developerstudio12.6/bin/CC -DoraGST_EXPORTS -fpic -m64 -std=c++03 -g -KPIC -I/export/opt/ora12cg3d/product/12.1.0/dbhome_1/rdbms/public -o CMakeFiles/oraGST.dir/oGST_manual.cpp.o -c /export/home/paul/test/oGST_manual.cpp
and
/opt/developerstudio12.6/bin/CC -KPIC -fpic -m64 -std=c++03 -g -m64 -std=c++03 -G -hliboraGST.so -o liboraGST.so CMakeFiles/oraGST.dir/oGST_manual.cpp.o -lstdc++
ldd -d liboraGST.so yields:
libstdc++.so.6 => /opt/developerstudio12.6/lib/compilers/CC-gcc/lib/amd64/libstdc++.so.6
libgcc_s.so.1 => /opt/developerstudio12.6/lib/compilers/CC-gcc/lib/amd64/libgcc_s.so.1
libstatomic.so.1 => /opt/developerstudio12.6/lib/compilers/atomic/amd64/libstatomic.so.1
libCrunG3.so.1 => /usr/lib/64/libCrunG3.so.1
libm.so.2 => /lib/64/libm.so.2
librt.so.1 => /lib/64/librt.so.1
libc.so.1 => /lib/64/libc.so.1
For you reference you can find the output of strings -a at https://nopaste.xyz/?50daded482074bd3#9KLZaMYDiVBEFLLrTFV1UOY5ZRaZWnz006iBwSnCzMk=

Related

Configuring compilers on Mac M1 (Big Sur, Monterey) for Rcpp and other tools

I'm trying to use packages that require Rcpp in R on my M1 Mac, which I was never able to get up and running after purchasing this computer. I updated it to Monterey in the hope that this would fix some installation issues but it hasn't. I tried running the Rcpp check from this page but I get the following error:
> Rcpp::sourceCpp("~/github/helloworld.cpp")
ld: warning: directory not found for option '-L/opt/R/arm64/gfortran/lib/gcc/aarch64-apple-darwin20.2.0/11.0.0'
ld: warning: directory not found for option '-L/opt/R/arm64/gfortran/lib'
ld: library not found for -lgfortran
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [sourceCpp_4.so] Error 1
clang++ -arch arm64 -std=gnu++14 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I../inst/include -I"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/Rcpp/include" -I"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/RcppArmadillo/include" -I"/Users/afredston/github" -I/opt/R/arm64/include -fPIC -falign-functions=64 -Wall -g -O2 -c helloworld.cpp -o helloworld.o
clang++ -arch arm64 -std=gnu++14 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/opt/R/arm64/lib -o sourceCpp_4.so helloworld.o -L/Library/Frameworks/R.framework/Resources/lib -lRlapack -L/Library/Frameworks/R.framework/Resources/lib -lRblas -L/opt/R/arm64/gfortran/lib/gcc/aarch64-apple-darwin20.2.0/11.0.0 -L/opt/R/arm64/gfortran/lib -lgfortran -lemutls_w -lm -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
Error in Rcpp::sourceCpp("~/github/helloworld.cpp") :
Error 1 occurred building shared library.
I get that it can't "find" gfortran. I installed this release of gfortran for Monterey. When I type which gfortran into Terminal, it returns /opt/homebrew/bin/gfortran. (Maybe this version of gfortran requires Xcode tools that are too new—it says something about 13.2 and when I run clang --version it says 13.0—but I don't see another release of gfortran for Monterey?)
I also appended /opt/homebrew/bin: to PATH in R so it looks like this now:
> Sys.getenv("PATH")
[1] "/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin:/Applications/RStudio.app/Contents/MacOS/postback"
Other things I checked:
Xcode command line tools is installed (which clang returns /usr/bin/clang).
Files ~/.R/Makevars and ~/.Renviron don't exist.
Here's my session info:
R version 4.1.1 (2021-08-10)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Monterey 12.1
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] compiler_4.1.1 tools_4.1.1 RcppArmadillo_0.10.7.5.0
[4] Rcpp_1.0.7
Background
Currently (2023-02-20), CRAN builds R 4.2 binaries for Apple silicon using Apple Clang from Command Line Tools for Xcode 13.1 and using an experimental fork of GNU Fortran 12.
If you obtain R from CRAN (i.e., here), then you need to replicate CRAN's compiler setup on your system before building R packages that contain C/C++/Fortran code from their sources (and before using Rcpp, etc.). This requirement ensures that your package builds are compatible with R itself.
A further complication is the fact that Apple Clang doesn't support OpenMP, so you need to do even more work to compile programs that make use of multithreading. You could circumvent the issue by building R itself, all R packages, and all external libraries from sources with LLVM Clang, which does support OpenMP, but that approach is onerous and "for experts only".
There is another approach that has been tested by a few people, including Simon Urbanek, the maintainer of R for macOS. It is experimental and also "for experts only", but it works on my machine and is much simpler than learning to build R and other libraries yourself.
Instructions for obtaining a working toolchain
Warning: These come with no warranty and could break at any time. Some level of familiarity with C/C++/Fortran program compilation, Makefile syntax, and Unix shells is assumed. Everyone is encouraged to consult official documentation, which is more likely to be maintained than answers on SO. As usual, sudo at your own risk.
I will try to address compilers and OpenMP support at the same time. I am going to assume that you are starting from nothing. Feel free to skip steps you've already taken, though you might find a fresh start helpful.
I've tested these instructions on a machine running Big Sur, but they should also work on Monterey and Ventura.
Download an R 4.2 binary from CRAN here and install. Be sure to select the binary built for Apple silicon.
Run
$ sudo xcode-select --install
in Terminal to install the latest release version of Apple's Command Line Tools for Xcode, which includes Apple Clang. You can obtain earlier versions from your browser here. However, the version that you install should not be older than the one that CRAN used to build your R binary.
Download the GNU Fortran binary provided here and install by unpacking to root:
$ curl -LO https://mac.r-project.org/tools/gfortran-12.0.1-20220312-is-darwin20-arm64.tar.xz
$ sudo tar xvf gfortran-12.0.1-20220312-is-darwin20-arm64.tar.xz -C /
$ sudo ln -sfn $(xcrun --show-sdk-path) /opt/R/arm64/gfortran/SDK
The last command updates a symlink inside of the installation so that it points to the SDK inside of your Command Line Tools installation.
Download an OpenMP runtime suitable for your Apple Clang version here and install by unpacking to root. You can query your Apple Clang version with clang --version. For example, I have version 1300.0.29.3, so I did:
$ curl -LO https://mac.r-project.org/openmp/openmp-12.0.1-darwin20-Release.tar.gz
$ sudo tar xvf openmp-12.0.1-darwin20-Release.tar.gz -C /
After unpacking, you should find these files on your system:
/usr/local/lib/libomp.dylib
/usr/local/include/ompt.h
/usr/local/include/omp.h
/usr/local/include/omp-tools.h
Add the following lines to $(HOME)/.R/Makevars, creating the file if necessary.
CPPFLAGS += -I/usr/local/include -Xclang -fopenmp
LDFLAGS += -L/usr/local/lib -lomp
Test that you are able to use R to compile a C or C++ program with OpenMP support while linking relevant libraries from the GNU Fortran installation (indicated by the -l flags in the output of R CMD CONFIG FLIBS).
The most transparent approach is to use R CMD SHLIB directly. In a temporary directory, create an empty source file omp_test.c and add the following lines:
#ifdef _OPENMP
# include <omp.h>
#endif
#include <Rinternals.h>
SEXP omp_test(void)
{
#ifdef _OPENMP
Rprintf("OpenMP threads available: %d\n", omp_get_max_threads());
#else
Rprintf("OpenMP not supported\n");
#endif
return R_NilValue;
}
Compile it:
$ R CMD SHLIB omp_test.c $(R CMD CONFIG FLIBS)
Then call the compiled C function from R:
$ R -e 'dyn.load("omp_test.so"); invisible(.Call("omp_test"))'
OpenMP threads available: 8
If the compiler or linker throws an error, or if you find that OpenMP is still not supported, then one of us has made a mistake. Please report any issues.
Note that you can implement the same test using Rcpp, if you don't mind installing it:
library(Rcpp)
registerPlugin("flibs", Rcpp.plugin.maker(libs = "$(FLIBS)"))
sourceCpp(code = '
#ifdef _OPENMP
# include <omp.h>
#endif
#include <Rcpp.h>
// [[Rcpp::plugins(flibs)]]
// [[Rcpp::export]]
void omp_test()
{
#ifdef _OPENMP
Rprintf("OpenMP threads available: %d\\n", omp_get_max_threads());
#else
Rprintf("OpenMP not supported\\n");
#endif
return;
}
')
omp_test()
OpenMP threads available: 8
References
Everything is a bit scattered:
R Installation and Administration manual [link]
Writing R Extensions manual [link]
R for macOS Developers web page [link]
I resolved this issue by adding a path to the homebrew installation of gfortran to my ~/.R/Makevars following these instructions: https://pat-s.me/transitioning-from-x86-to-arm64-on-macos-experiences-of-an-r-user/#gfortran
I just avoided the issue until MacOS had things working more smoothly. so I either Windows Developer Virtual Machine (VM) or run my code development in another environment. I'm not too impressed with the updated and "faster" chipset, but that it doesn't work with much. Slow to implement and work-a-rounds often are a must.
Tested the following process for making multithread data.table work in a M2 MacBook Pro (macOS Monterey)
Steps are mostly the same with this answer by the user inferator.
Download and install R from CRAN
Download and install RStudio with developer tools
Run the following commands in terminal to install OpenMP
curl -O https://mac.r-project.org/openmp/openmp-12.0.1-darwin20-Release.tar.gz
sudo tar fvxz openmp-12.0.1-darwin20-Release.tar.gz -C /
Add compiler flags to connect clan w/ OpenMP. In terminal, write the following:
cd ~
mkdir .R
nano .R/Makevars
Inside the opened Makevars file paste the following lines. Once finished, hit command+O and then Enter to save. Do a command+X to close the editor.
CPPFLAGS += -Xclang -fopenmp
LDFLAGS += -lomp
Download and run the installer for gfortran by downloading gfortran-ARM-12.1-Monterey.dmg from the respective GitHub repo
This concludes the steps regarding enabling OpenMP and (hopefully) Rcpp in R under a M2 chip system.
Now, for testing that everything works with data.table I did the following
Open RStudio and run
install.packages("data.table", type = "source")
If everything is done correctly, the package should compile without any errors and return the following when running getDTthreads(verbose = TRUE):
OpenMP version (_OPENMP) 201811
omp_get_num_procs() 8
R_DATATABLE_NUM_PROCS_PERCENT unset (default 50)
R_DATATABLE_NUM_THREADS unset
R_DATATABLE_THROTTLE unset (default 1024)
omp_get_thread_limit() 2147483647
omp_get_max_threads() 8
OMP_THREAD_LIMIT unset
OMP_NUM_THREADS unset
RestoreAfterFork true
data.table is using 4 threads with throttle==1024. See ?setDTthreads.
[1] 4

Linking error when compiling Crypto++ for ARMHF

I'm trying to compile the crypto++ library to run for the armhf architecture. I'm following the method provided in this answer. I tweaked the setenv-embed.sh to match my system's configuration. The output of running . ./setenv-embed.sh is
CPP: /usr/bin/arm-linux-gnueabihf-cpp
CXX: /usr/bin/arm-linux-gnueabihf-g++
AR: /usr/bin/arm-linux-gnueabihf-ar
LD: /usr/bin/arm-linux-gnueabihf-ld
RANLIB: /usr/bin/arm-linux-gnueabihf-gcc-ranlib-4.8
ARM_EMBEDDED_TOOLCHAIN: /usr/bin
ARM_EMBEDDED_CXX_HEADERS: /usr/arm-linux-gnueabihf/include/c++/4.8.2
ARM_EMBEDDED_FLAGS: -march=armv7-a mfloat-abi=hard -mfpu=neon -I/usr/arm-linux-gnueabihf/include/c++/4.8.2 -I/usr/arm-linux-gnueabihf/include/c++/4.8.2/arm-linux-gnueabihf
ARM_EMBEDDED_SYSROOT: /usr/arm-linux-gnueabihf
which indicates that the correct compilers have been found. However, when I build the library using make I run into the following error
/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/bin/‌​ld: cannot find /usr/arm-linux-gnueabihf/lib/libc.so.6 inside /usr/arm-linux-gnueabihf
/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/bin/‌​ld: cannot find /usr/arm-linux-gnueabihf/lib/libc_nonshared.a inside /usr/arm-linux-gnueabihf
/usr/lib/gcc-cross/arm-linux-gnueabihf/4.8/../../../../arm-linux-gnueabihf/bin/‌​ld: cannot find /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 inside /usr/arm-linux-gnueabihf
But when I open the location /usr/arm-linux-gnueabihf/lib I can find all the three error files mentioned above ie libc.so.6, libc_nonshared.a and ld-linux-armhf.so.3
I'm trying to compile the library for Beaglebone, if that helps.
Update 1:
The results of running make -f GNUmakefile-cross system after doing a fresh git pull
hassan#hassan-Inspiron-7537:~/cryptopp-armhf$ make -f GNUmakefile-cross system
CXX: /usr/bin/arm-linux-gnueabihf-g++
CXXFLAGS: -DNDEBUG -g2 -Os -Wall -Wextra -DCRYPTOPP_DISABLE_ASM -march=armv7-a -mfloat-abi=hard -mfpu=neon -mthumb -I/usr/arm-linux-gnueabihf/include/c++/4.8.2 -I/usr/arm-linux-gnueabihf/include/c++/4.8.2/arm-linux-gnueabihf --sysroot=/usr/arm-linux-gnueabihf -Wno-type-limits -Wno-unknown-pragmas
LDLIBS:
GCC_COMPILER: 1
CLANG_COMPILER: 0
INTEL_COMPILER: 0
UNALIGNED_ACCESS:
UNAME: Linux hassan-Inspiron-7537 3.13.0-35-generic #62-Ubuntu SMP Fri Aug 15 01:58:42 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
MACHINE:
SYSTEM:
RELEASE:
make: Nothing to be done for `system'.
The problem is simple. It is in the --sysroot option. The value of this option is /usr/arm-linux-gnueabihf/ and it is used by the linker and the resulting library folder becomes
/usr/arm-linux-gnueabihf/usr/arm-linux-gnueabihf/lib/
I removed the --sysroot option from line 68 in the file GNUmakefile-cross and everything compiled and linked OK.
However, I couldn't run the example on my BeagleBone Black because of mismatch of some shared libraries versions. But this wasn't a real problem for me, because in my application I link crypto++ statically, not dynamically.
Based on Crosswalking's research I think I can explain what is going on. I don't think I agree with the assessment "The problem is simple. It is in the --sysroot option" since the Crypto++ environment script and makefile are doing things as expected.
I think Crosswalking's answer could be how to work around it; but see open questions below. The following is from Crypto++ Issue 134: setenv-embedded.sh and GNUmakefile-cross:
I think this another distro problem, similar to g++-arm-linux-gnueabi
cannot compile a C++ program with
--sysroot.
It might be a Ubuntu problem or a Debian problem if it is coming from
upstream.
When cross-compiling, we expect the following (using ARMHF):
SYSROOT is /usr/arm-linux-gnueabihf
INCLUDEDIR is /usr/arm-linux-gnueabihf/include
LIBDIR is /usr/arm-linux-gnueabihf/lib
BINDIR is /usr/arm-linux-gnueabihf/bin
How LIBDIR morphed into into
/usr/arm-linux-gnueabihf/usr/arm-linux-gnueabihf/lib/ (i.e.,
$SYSROOT/$SYSROOT/lib) is a mystery. But in all fairness, building
GCC is not a trivial task.
You should probably file a bug report with Debian or Ubuntu (or
whomever provides the toolchain).
The open question for me is, since $SYSROOT/lib is messed up, then is $SYSROOT/include messed up, too?
If the include directory is also messed up, then the cross compile is using the host's include files, and not the target include files. That will create hard to diagnose problems later.
If both $SYSROOT/include and $SYSROOT/lib are messed up, then its not enough to simply remove --sysroot. Effectively, this is what has to be done:
# Exported by setenv-embedded
export=ARM_EMBEDDED_SYSROOT=/usr/arm-linux-gnueabihf
# Used by the makefile
-I $ARM_EMBEDDED_SYSROOT/$ARM_EMBEDDED_SYSROOT/include
-L $ARM_EMBEDDED_SYSROOT/$ARM_EMBEDDED_SYSROOT/lib
Which means we should be able to do the following:
# Exported by setenv-embedded
export=ARM_EMBEDDED_SYSROOT=/usr/arm-linux-gnueabihf/usr/arm-linux-gnueabihf
# Used by the makefile
--sysroot="$ARM_EMBEDDED_SYSROOT"
Finally, this looks a lot like Ubuntu's Bug 1375071: g++-arm-linux-gnueabi cannot compile a C++ program with --sysroot. The bug report specifically calls out ... the built-in paths use an extra "/usr/arm-linux-gnueabi".
We need the paths:
A) /usr/arm-linux-gnueabi/include/c++/4.7.3 B)
/usr/arm-linux-gnueabi/include/c++/4.7.3/arm-linux-gnueabi
But the built-in paths tries to use:
C) /usr/arm-linux-gnueabi/usr/arm-linux-gnueabi/include/c++/4.7.3
D)
/usr/arm-linux-gnueabi/usr/arm-linux-gnueabi/include/c++/4.7.3/arm-linux-gnueabi/sf
E)
/usr/arm-linux-gnueabi/usr/arm-linux-gnueabi/include/c++/4.7.3/backward
Notice the built-in paths use an extra "/usr/arm-linux-gnueabi"

Clang/LLVM on Eclipse (Mac)

I am trying to run Eclipse with the Clang compiler without success. First I went here http://clang.llvm.org/get_started.html and followed the instructions 1 through 8 successfully. I also installed the llvm toolchain via Eclipse marketplace.
What do I do next to successfully compile with Clang? From the installation I have two folders, llvm and build, where do I put them? How do I connect this to Eclipse?
I also downloaded lld in case I needed it since the llvm-ld doesn't work anymore. Below is my error message. I'll be so grateful if someone can help me figure this out! I've wasted a lot of hours on this.
20:09:47 **** Incremental Build of configuration Debug for project recursion ****
Info: Internal Builder is used for build
clang -O0 -emit-llvm -g3 -Wall -c -fmessage-length=0 -o recursiveprint.bc ../recursiveprint.c
lld -v -native -o recursion recursiveprint.bc
Cannot run program "lld": Unknown reason
Error: Program "lld" not found in PATH
PATH=[/usr/bin:/bin:/usr/sbin:/sbin]
20:09:47 Build Finished (took 74ms)

Debug symbol bug with MacPorts installed GCC 4.9?

I have recently installed GCC 4.9.2 (port name gcc49) through MacPorts. I am quite happy with its new features such as colorized diagnostics and C++1y/C++14 support improvements, etc.
However, since I started to compile code using GCC 4.9.2, I realized that it is not generating debug symbol directory *.dSYM and gdb says "no debugging symbols found" when I try to debug a program I compiled with -g flag.
Is this a MacPorts specific bug or is there a problem with GCC 4.9?
Thanks
It is not a MacPorts specific issue. MacPorts doesn't really do much to customize the gcc ports.
If you want to create a dSYM bundle and strip your executable, you should just do something like:
gcc-mp-4.9 -g3 -c example.c
gcc-mp-4.9 example.o -o example
dsymutil --out example.dSYM example
strip -S -x example
As a side note, if you want C++11/C++14 support, I suggest you use the clang-3.5 port as that will allow you to use libc++ from the system instead of libstdc++ from MacPorts (and allow you to use system and MacPorts C++ libraries rather than just the STL). Also, lldb is really the preferred debugger for OS X these days.

how to port c/c++ applications to legacy linux kernel versions

Ok, this is just a bit of a fun exercise, but it can't be too hard compiling programmes for some older linux systems, or can it?
I have access to a couple of ancient systems all running linux and maybe it'd be interesting to see how they perform under load. Say as an example we want to do some linear algebra using Eigen which is a nice header-only library. Any chance to compile it on the target system?
user#ancient:~ $ uname -a
Linux local 2.2.16 #5 Sat Jul 8 20:36:25 MEST 2000 i586 unknown
user#ancient:~ $ gcc --version
egcs-2.91.66
Maybe not... So let's compile it on a current system. Below are my attempts, mainly failed ones. Any more ideas very welcome.
Compile with -m32 -march=i386
user#ancient:~ $ ./a.out
BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 53: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
Compile with -m32 -march=i386 -static: Runs on all fairly recent kernel versions but fails if they are slightly older with the well known error message
user#ancient:~ $ ./a.out
FATAL: kernel too old
Segmentation fault
This is a glibc error which has a minimum kernel version it supports, e.g. kernel 2.6.4 on my system:
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.6.4, not stripped
Compile glibc myself with support for the oldest kernel possible. This post describes it in more detail but essentially it goes like this
wget ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.bz2
tar -xjf glibc-2.14.tar.bz2
cd glibc-2.14
mkdir build; cd build
../configure --prefix=/usr/local/glibc_32 \
--enable-kernel=2.0.0 \
--with-cpu=i486 --host=i486-linux-gnu \
CC="gcc -m32 -march=i486" CXX="g++ -m32 -march=i486"
make -j 4
make intall
Not sure if the --with-cpu and --host options do anything, most important is to force the use of compiler flags -m32 -march=i486 for 32-bit builds (unfortunately -march=i386 bails out with errors after a while) and --enable-kernel=2.0.0 to make the library compatible with older kernels. Incidentially, during configure I got the warning
WARNING: minimum kernel version reset to 2.0.10
which is still acceptable, I suppose. For a list of things which change with different kernels see ./sysdeps/unix/sysv/linux/kernel-features.h.
Ok, so let's link against the newly compiled glibc library, slightly messy but here it goes:
$ export LIBC_PATH=/usr/local/glibc_32
$ export LIBC_FLAGS=-nostdlib -L${LIBC_PATH} \
${LIBC_PATH}/crt1.o ${LIBC_PATH}/crti.o \
-lm -lc -lgcc -lgcc_eh -lstdc++ -lc \
${LIBC_PATH}/crtn.o
$ g++ -m32 -static prog.o ${LIBC_FLAGS} -o prog
Since we're doing a static compile the link order is important and may well require some trial and error, but basically we learn from what options gcc gives to the linker:
$ g++ -m32 -static -Wl,-v file.o
Note, crtbeginT.o and crtend.o are also linked against which I didn't need for my programmes so I left them out. The output also includes a line like --start-group -lgcc -lgcc_eh -lc --end-group which indicates inter-dependence between the libraries, see this post. I just mentioned -lc twice in the gcc command line which also solves inter-dependence.
Right, the hard work has paid off and now I get
$ file ./prog
./prog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.0.10, not stripped
Brilliant I thought, now try it on the old system:
user#ancient:~ $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
This, again, is a glibc error message from ./nptl/sysdeps/i386/tls.h. I fail to understand the details and give up.
Compile on the new system g++ -c -m32 -march=i386 and link on the old. Wow, that actually works for C and simple C++ programmes (not using C++ objects), at least for the few I've tested. This is not too surprising as all I need from libc is printf (and maybe some maths) of which the interface hasn't changed but the interface to libstdc++ is very different now.
Setup a virtual box with an old linux system and gcc version 2.95. Then compile gcc version 4.x.x ... sorry, but too lazy for that right now ...
???
Have found the reason for the error message:
user#ancient $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
It's because glibc makes a system call to a function which is only available since kernel 2.4.20. In a way it can be seen as a bug of glibc as it wrongly claims to be compatible with kernel 2.0.10 when it requires at least kernel 2.4.20.
The details:
./glibc-2.14/nptl/sysdeps/i386/tls.h
[...]
/* Install the TLS. */ \
asm volatile (TLS_LOAD_EBX \
"int $0x80\n\t" \
TLS_LOAD_EBX \
: "=a" (_result), "=m" (_segdescr.desc.entry_number) \
: "0" (__NR_set_thread_area), \
TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \
[...]
_result == 0 ? NULL \
: "set_thread_area failed when setting up thread-local storage\n"; })
[...]
The main thing here is, it calls the assembly function int 0x80 which is a system call to the linux kernel which decides what to do based on the value of eax, which is set to
__NR_set_thread_area in this case and is defined in
$ grep __NR_set_thread_area /usr/src/linux-2.4.20/include/asm-i386/unistd.h
#define __NR_set_thread_area 243
but not in any earlier kernel versions.
So the good news is that point "3. Compiling glibc with --enable-kernel=2.0.0" will probably produce executables which run on all linux kernels >= 2.4.20.
The only chance to make this work with older kernels would be to disable tls (thread-local storage) but which is not possible with glibc 2.14, despite the fact it is offered as a configure option.
The reason you can't compile it on the original system likely has nothing to do with kernel version (it could, but 2.2 isn't generally old enough for that to be a stumbling block for most code). The problem is that the toolchain is ancient (at the very least, the compiler). However, nothing stops you from building a newer version of G++ with the egcs that is installed. You may also encounter problems with glibc once you've done that, but you should at least get that far.
What you should do will look something like this:
Build latest GCC with egcs
Rebuild latest GCC with the gcc you just built
Build latest binutils and ld with your new compiler
Now you have a well-built modern compiler and (most of a) toolchain with which to build your sample application. If luck is not on your side you may also need to build a newer version of glibc, but this is your problem - the toolchain - not the kernel.