I have a package that depends on Rcpp and uses two other libraries compiled from sub-directories in src/. The package builds fine on Mac OSX using a clang compiler. However, on an RStudio Ubuntu server, it fails to build. The build's first two steps (creating the static libraries in the sub directories to link in) work fine and I can see sensible build commands like the following taking place:
g++ -Wall -I../../inst/include/ --std=c++11 -lhts -L../htslib/ -lz -lm -c -o someLibFile.o someLibFile.cpp
However, in the very last step of the build process where it tries to build the Rcpp code and bind to the library, for some reason it appears to compleletey fail to put the compiler command in front (g++) and only outputs the second half of the command.
-o mypackage.so RcppExports.o temp.o -lhts -lpbbam -Lpbbam/ -L/htslib/ -Lpbbam/ -L/mnt/software/r/R/3.1.1/usr/lib/R/lib -lR
In contrast, on the Mac it builds just fine, appending clang++ and other flags in front of this final command:
clang++ -std=c++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/lib -o pbbamr.so LoadData.o RcppExports.o temp.o -lhts -lpbbam -Lpbbam/ -Lhtslib/ -Lpbbam/ -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
How do I make it use the g++ compiler on Ubuntu at this step? I have a custom Makevars file, but it is there just to build the dependencies in the sub-directory, so I don't know why that would cause any problems (since it works on Mac OSX).
More Information
The compiler seems to be found if I delete my Makevars file. However, the Makevars file I am using is essentially a direct copy of the example given in the R extensions guide with one addition to enable C++11:
CXX_STD = CXX11
.PHONY: all mylibs
all: $(SHLIB)
$(SHLIB): mylibs
mylibs:
(cd subdir; make)
With the line CXX_STD removed, it does stick a compiler in front of the command.
Briefly:
What is your R installation? You should probably run the binaries provided by Michael via CRAN; they are based on my Debian upload; I run these too on a bunch of machines
The reason is that R 'remembers' its compile-time settings via $RHOME/etc/Makefconf. This should just be CXX=g+=.
When you install r-base-dev (from Ubuntu or the newer version from CRAN) you also get the build-essential package as well as all common dependencies. With that things just work.
If however you are doing something special or local, well then you have to deal with your local changes. The basic Ubuntu setup is used by thousands of people and daily jobs--including eg Travis builds for countless GitHub repos.
This is caused by using an outdated/unusual R installation which has poor support for C++11. The best way to resolve his is to upgrade to a more recent version of R, or use a standard R install (sudo apt-get install r-base-dev). A poor work around is described below.
Problems Cause and Bad Work Around
When writing R extension that use C++11, one often sets CXX_STD = CXX11 in the Makevars file or list SystemRequirements: C++11 in the DESCRIPTION file. These will trigger R to use the compiler set by the following flags in the Makeconf file (located at file.path(R.home(), "etc/Makeconf")).
CXX1X
CXX1XFLAGS
CXX1XPICFLAGS
CXX1XSTD
Note that some of these may be set in this file, but not all of them might be there indicating a problem. In the event there is a problem with these settings or they are not set, R appears to use the empty string "" as the compiler/linker for the C++ code, leading to the problem shown above where no compiler argument is given.
If upgrading is not an option and you need to deploy on a known machine, one work around is to manually setup for C++11 by making a more idiosyncratic Makevars file. For example, you could:
Remove the CXX_STD=CXX11 line from the Makevars file.
Remove SystemRequirements: C++11 from the DESCRIPTION file.
Add --std=c++11 and any other requirements needed to PKG_CPPFLAGS, PKG_CFLAGS, PKG_CXXFLAGS or whatever variable is being used to compile your code, to manually set the needed flags (assuming the machine's compiler actually does support C++11).
The above solution is not particularly robust, but can be used as a work around in case the machine cannot be upgraded.
Thanks to #DirkEddelbuettel for not only writing Rcpp but being willing to support it on StackOverflow and help with issues like this.
Related
Believe me I've spent quite some time Googling without much of an outcome.
I'm writing a very basic OS as a fun project. It, for obvious reasons, needs to be compiled into a standalone form (i686-elf in my case). However I've decided that pure C isn't enough for me and that I'd love to use C++. So I've written a bit of code and it seemed to work, so I went on and all of sudden I kept getting the same error despite no obvious problem with the code.
./sh/../obj/class_string.o:(.eh_frame+0x4f): undefined reference to __gxx_personality_v0'
./sh/../obj/kernel.o:(.eh_frame+0x13): undefined reference to __gxx_personality_v0'
/home/natiiix/crosscompiler/out/path/bin/../lib/gcc/i686-elf/6.1.0/libgcc.a(unwind-dw2.o): In function read_encoded_value_with_base':
/home/natiiix/crosscompiler/out/src/build-gcc/i686-elf/libgcc/../../../gcc-6.1.0/libgcc/unwind-pe.h:257: undefined reference to abort'
After a bit of Googling I've figured out the problem must be that my g++ cross-compiler lacks c++ libs, which turned out to be true. It indeed contains just libgcc and libgcov. So I've figured out I'd get them somehow, but it turned out to be quite a difficult task to do. It's virtually impossible to find the already compiled libstdc++.a. So I had to compile it myself and as I'm not particularly familiar with makefile it definitely wasn't easy to figure out.
Finally I've found a bash script that somewhat allowed me to do what I needed. It downloads gcc 6.1.0, binutils, configures both and runs make, make install. That would be really nice if it actually worked. The compiler itself works like a charm as far as I can tell at least, but the library won't work no matter what I do since, at least I suspect, it is being built for a different target platform for some reason. It appears that libstdc++ simply cannot be built for i686-elf or something along the lines.
gccbuild.sh:
#!/bin/bash
set -e
if [ "$#" -ne 1 ]; then
echo "Supply one parameter: the target to use!!"
exit 1
fi
sudo apt install libgmp3-dev libmpfr-dev libisl-dev libcloog-isl-dev libmpc-dev texinfo -y
cd "$(dirname "$0")"
rm -rfv out/
mkdir out/
cd out/
rm -rfv path/
mkdir path/
rm -rfv src/
mkdir src/
cd src/
wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.26.tar.gz
wget ftp://ftp.gnu.org/gnu/gcc/gcc-6.1.0/gcc-6.1.0.tar.gz
tar -xvzf binutils-2.26.tar.gz
tar -xvzf gcc-6.1.0.tar.gz
export PREFIX="$(pwd)/../path/"
export TARGET=$1
export PATH="$PREFIX/bin:$PATH"
rm -rfv build-binutils/
mkdir build-binutils/
cd build-binutils/
../binutils-2.26/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-werror
make
make install
cd ..
rm -rfv build-gcc/
mkdir build-gcc/
cd build-gcc/
../gcc-6.1.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
../gcc-6.1.0/libstdc++-v3/configure --host=$TARGET --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --disable-libstdcxx-threads
make
make install
My compile / link script (so that you can see the g++ arguments):
${BASH_SOURCE%/*}/../../crosscompiler/out/path/bin/i686-elf-g++ -c ${BASH_SOURCE%/*}/../src/*.cpp --std=c++11 -ffreestanding -O2 -Wall -Wextra
echo moving object files from active directory to obj/
mv *.o ${BASH_SOURCE%/*}/../obj/
${BASH_SOURCE%/*}/../../crosscompiler/out/path/bin/i686-elf-g++ -T ${BASH_SOURCE%/*}/../src/linker.ld -o ${BASH_SOURCE%/*}/../bin/kokos.bin -ffreestanding -O2 -nostdlib ${BASH_SOURCE%/*}/../obj/*.o -lgcc -lstdc++ -lsupc++
When I try to link those libraries (versions of libstdc++ and libsupc++ that appear to be elf32-i386, which is as close as they get to the i686-elf) I stop getting the undefined reference to __gxx_personality_v0, but I still get a handful of undefined references to what appear to be C functions. (abort, strlen, malloc, free)
The whole problem can be avoided by not using templates, class destructors and some more c++ specific stuff (ironically classes alone seem to work just fine for the most part), but it doesn't seem like a very good solution to me. I'd rather have access to such things.
Could someone please explain to me what have I done wrong?
It is not clear from your post what exact result you want to get. Below there are few observations that may help you to figure out what your real problems are.
First, if you need 32-bit code to be compiled on your (I guess) 64-bit Ubuntu host, you do not need a cross toolchain, just compile it with -m32.
If you want your code to be optimized for specific CPU variant, just use appropriate -march=, -mcpu= and -mtune= options.
If you need your 32-bit program to be statically linked with C++ libraries, then on Ubuntu you just need to install a package libstdc++-6-dev:i386. Run sudo apt-get install libstdc++-6-dev:i386, it will also install all necessary dependencies. Then just compile your program with gcc -m32 -static.
If you need to use standard libraries optimized for specific CPU, rather than for generic i386 then you need to build them manually. This is true not only for libstdc++, but also for libc (IIRC, Ubuntu 16.04 still uses generic -march=i386 option to build libc, Ubuntu 16.10 uses -march=i686).
You got the undefined references from your link output because you are using -nostdlib and -lstdc++ but not -lc. libstdc++ uses the functions from standard C library,so you need it.
As you develop an OS kernel and you need a freestanding environment, I suppose that you really do not need standard libraries. In that case refer to C++ standard, clause 17.6.1.3, to find which standard headers you may use in your application. You have to use -lsupc++ -lgcc on your compiler command line and additionally you need -lgcc_eh if you use exception handling (and libgcc_eh.a is where __gxx_personality_v0 comes from). Do not use -lstdc++ in a freestanding environment!
Hope this helps a bit and have a good luck!
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"
I wanted to use latest g++ compiler(4.9.1) on suse linux, but suse only supports an older g++ version. So, I took a latest source code from one of the gnu mirror sites and compiled it myself. Everything went fine. But when I tried to compile my test code using the built g++, the compilation fails with error,
"/root/home/include/c++/4.9.1/x86_64-unknown-linux-gnu/bits/os_defines.h:39:22: fatal error: features.h: No such file or directory".
I can find a "features.h" in "/root/home/include/c++/4.9.1/parallel", but I feel that it should be there in "/root/home/include/c++/4.9.1/" itself.
I copied "/root/home/include/c++/4.9.1/parallel/features.h" to "/root/home/include/c++/4.9.1/" just to see what happens. Now it complains with error "whcar.h" not found.
Have I missed something.
Here are the steps I followed to build g++.
1. /root/home/gcc_build/objdir# ../gcc-4.9.1/configure --prefix=/root/home/ --disable-multilib
2. /root/home/gcc_build/objdir# make -j16
3. /root/home/gcc_build/objdir# make install
4. /root/home/gcc_build/test# /root/home/bin/g++ --sysroot /root/home -m64 test.cpp
I resolved the issue by removing sysroot option and pointing c++ include and library path to my home directory. One thing I noticed was that the g++ source does not come with libc and c header files, and libc has to be installed seperately. But with sysroot option, g++ was trying to look all the header files in my home directory.
Below is the command I used to successfully compile the code.
/root/home/bin/g++ -I /root/home/include/c++/4.9.1 -L /root/home/lib64 -Wl,--rpath=/root/home/lib64 --std=c++0x -m64 test.cpp
Take a look at the GCC Directory Options. It is important to use the correct "specifier" as well (-isystem, -L, -B, -I etc)
Gooday everyone
I'm fairly new to ubuntu C programing although I'm
rather experienced in C programing in windows.
I have recently come accross a number of codes written
in 2005 which I'm interested in learning how they work.
Those codes needs BOOST library to compile, however they won't
compile on the newest BOOST version present on my ubuntu 12.04.
I set the gcc compiler on lenient so that it ignores all those error
messages. The code did compile and ran afterwards.
However, when I used GDB debugger to watch how the program flows
I noticed that there are likely errors in the way the program runs
due to using a different BOOST version rather than it's original. Hence
I like to install the BOOST version corresponding to the code I downloaded.
To do that, I installed Ubuntu 5.04 and BOOST 1.33.0 which seemed to have been created in late 2005. I downloaded it
but I didnt found any detailed instruction on how to install it.
Only vague description on using BOOST jam, I played around with BOOST
jam for quite awhile without success.
And this old BOOST does not have installation commands like
"sudo apt-install boost-dev" style option
Thus I like to ask if anyone can give a easy to understand step by step instruction
on how to install the BOOST library downloaded from the above link.
like.....
step1: download boost jam from boost webpage
step2: unpack it in home/boost/ then type make configure
...and so on...
Big thanks for any useful info.
New Contents appended here
in response to the comments given
Hi, I went through the info given by your link and
managed to run the boost library examples given by your link.
That is, I can compile a single cpp file with the command
g++ -I boost_1_33_0 test.cpp -o test
(I'm keeping the boost library and the cpp file to be compiled in the
same folder)
However, the program package I'm interested in is build with make (not cmake).
I have some experience writting cmake files but not make files.
And I do not see any link to boost library command in the make file of the
program package. The readme file only has one sentence that says I
need to have boost installed without explaining what that meant.
I assume it means that either I have to build and do makeinstall the boost or
I could add some lines in the makefile for a link. I thought
maybe you can quickly point out whats missing in the makefile.
The readme file:
To compile, go into the moses directory and do 'make'. You'll need the
latest boost libraries. If compilation still fails for weird reasons,
you could try g++ with the -fpermissive (newer versions reject lots of
code that was ok with older ones). If you are going to be making
changes and recompiling frequently you'll probably want to disable -O3
in the makefile (I use templates liberally, so -O3 really speeds up
the code, but really slows down compilation).
And the makefile:
CC = g++
PROJ_NAME = moses
LINK_FLAGS = -Wall -Iutils/ -Itrees/ -Irewrite -I./ -Imodeling/ -Ifitness/ \
-Ialignment/ -Isim/ -Ilocal/ -O3
COMP_FLAGS = -Wall -Wno-sign-compare -Iutils/ -Itrees/ -Irewrite -I./ \
-Imodeling/ -Ifitness/ -Ialignment/ -Isim/ -Ilocal/ -O3
src := $(wildcard *.cc) $(wildcard utils/*.cc) $(wildcard trees/*.cc) $(wildcard modeling/*.cc) $(wildcard fitness/*.cc) $(wildcard alignment/*.cc) $(wildcard main/*.cc) $(wildcard rewrite/*.cc) $(wildcard sim/*.cc) $(wildcard local/*.cc)
obj := $(patsubst %.cc,%.o,$(src))
all: $(PROJ_NAME)
%.o: %.cc
$(CC) $(COMP_FLAGS) $< -c -o $#
$(PROJ_NAME): $(obj)
$(CC) $(LINK_FLAGS) $^ -o $(PROJ_NAME)
run:
$(PROJ_NAME)
clean:
find -regex ".*~\|.*\.o"|xargs rm -f
rm -f $(PROJ_NAME)
rm -f $(PROJ_NAME).exe*
depend:
makedepend -Y -- $(COMP_FLAGS) -- $(src)
utils/exceptions.o: utils/exceptions.h utils/utils.h
utils/io_util.o: utils/io_util.h utils/tree.h utils/basic_types.h
# ......lots more lines like that.........
I have an old instruction flying around here for Boost 1.34.1, which reads like this (project-specific stuff cut away):
unpack boost sources
cd into tools/jam/src
run ./build.sh to build bjam
cd into the main source directory
tools/jam/src/bin.linux/bjam threading=multi --layout=system --toolset=gcc --without-python variant=release --prefix=/usr/local install
The --without-python was necessary as the target system didn't have Python installed, which caused the build to fail messily.
Obviously you can / need to fiddle with the individual settings (like threading support, release vs. debug variant) to suit your needs, but it should be a good starting point.
If you need ICU support (for Boost.Regex and Boost.Locale), it gets more complicated...
Note that the build process has changed over the years; you shouldn't use the same procedure for more up-to-date boost versions. It's just what I used back then.
Edit:
As for the second part of your question, the Makefile doesn't need to refer to Boost explicitly if boost is installed in the standard system directories.
You do not have to state -I /usr/include for compilation as that is searched automatically; the same goes for -L /usr/lib during linkage.
The fact that the author of the Makefile copied the compiler flags into the linker flags verbatim doesn't really help intuitivity either... ;-)
If you have Boost in a custom directory (either the headers only, or by stating a custom directory in the --prefix option of my build instructions), you need to make the following modifications (look for "boost"):
LINK_FLAGS = -Wall -Iutils/ -Itrees/ -Irewrite -I./ -Imodeling/ -Ifitness/ \
-Ialignment/ -Isim/ -Ilocal/ -L /path/to/boost/libs -O3
COMP_FLAGS = -Wall -Wno-sign-compare -Iutils/ -Itrees/ -Irewrite -I./ \
-Imodeling/ -Ifitness/ -Ialignment/ -Isim/ -Ilocal/ \
-I /path/to/boost/includes -O3
That should do the trick. As the Makefile does not link any of the Boost binaries (e.g. -l boost_program_options or somesuch), it seems that it makes use of the Boost headers only, which would make the -L /path/to/boost/libs part (and, actually, the whole compilation step detailed above) superfluous. You should be able to get away with simply unpacking the sources and giving the header directory as additional include directory using -I /path/to/boost/headers.
Being perfectly satisfied with old-style Makefiles, I am looking for a simple alternative to libtool. I do not want to switch to automake, and I keep running into problems with libtool when I try to use it directly. The latest one is 'unsupported hardcode properties', and I am getting fed up with the lack of complete documentation that just tells me what is wrong this time...
I only want to compile a bunch of .o files with the right flags and then link them into a shared library, such that it works on as many platforms as possible. Is there anything out there that does just that and not force me to switch all of my other tools at the same time?
I not sure if it would fit info your workflow but I'd recommend looking at CMake. It works on Windows, Linux and Mac and should not force you to change any of your other tools. You'll have to judge its suitability yourself though.
There's jlibtool (which has nothing to do with java).
It's written in C, and can just be bundled with your source.
It was originally an apache project, but whoever was working it there seems to of abandoned it around 2004.
It was taken over by FreeRADIUS project maintainer Alan Dekok, who modernised the code and fixed a few niggling issues. We use it for the FreeRADIUS project (>= 3.0.0) to do all the build time linking.
Given your description in the comment to Milliams' answer,
I just want one tool that I tell: "give me the compiler flags so that I can compile these n files for use in a shared library, and then give me the commands to link them together",
then libtool may well be the simplest tool for the job. I know of no other alternative.
You are right that the documentation for using libtool with plain makefiles is practically nonexistent, but libtool certainly does not require you to switch to automake. Cross-platform libraries are difficult, and the price you have to pay for them is libtool. (Or maybe the discount price is libtool+automake+autoconf or CMake or Jam.)
slibtool (dl.midipix.org/slibtool, git://midipix.org/slibtool) is a libtool drop-in replacement, written in C. A single slibtool binary aims to seamlessly support both native and cross-builds, and the utility also provides some additional features (installation of .la files is optional, optional color-coded annotation, etc). The following minimal plain makefile demonstrates how to (cross-) build a library using slibtool.
CC = cc
LIBTOOL = slibtool
DESTDIR = destdir
all: libfoo.la
a.lo:
$(LIBTOOL) --mode=compile --tag=CC $(CC) -c a.c
libfoo.la: a.lo
$(LIBTOOL) --mode=link --tag=CC $(CC) -o libfoo.la -rpath /lib
install: all
mkdir -p destdir
$(LIBTOOL) --mode=install cp libfoo.la $(DESTDIR)
# the -rpath argument is required for semantic compatibility with libtool.
native build, default (both shared library and static library)
$ make
$ make install
native build, shared library only
$ make LIBTOOL=slibtool-shared
$ make install
native build, static library only
$ make LIBTOOL=slibtool-static
$ make install
cross-build, default
$ make CC=some-target-tuple-gcc
$ make install
cross-build, default, with lots of colors
$ make LIBTOOL=dlibtool CC=some-target-tuple-gcc
$ make install