How to build Static Binary for Tesseract? - c++

I am currently building Tesseract 4.0.0 from source (on Ubuntu 14.04 for context), using the instructions found on: https://github.com/tesseract-ocr/tesseract/wiki/Compiling
I am using the following ./configure parameters:
./configure --disable-openmp --disable-graphics --disable-opencl --enable-static LDFLAGS='-static -static-libgcc -static-libstdc++' --disable-shared
Followed by
make and sudo make install
The compiled binary I am running after is src/api/tesseract, which works as intended. The problem is that when I run ldd on this file, it actually shows dependencies.
Am I looking in the wrong spot for the static binary of Tesseract (I ran a find command in the entire repo and didn't see anything else that looked like an executable), or am I misunderstanding the meaning of a static binary - I am under the impression it is pretty much an executable version of Tesseract that does not require any dependencies to be pre installed.
If there is any problem with the configure options too please let me know. I do not believe that --disable-openmp --disable-graphics --disable-opencl impacts static vs shared linking but I am using those for my desired tesseract build so I included them for more context.

$ uname -a
Linux vm00 4.15.0-50-generic #54-Ubuntu SMP Mon May 6 18:46:08 UTC
2019 x86_64 x86_64 x86_64 GNU/Linux
$ echo $CFLAGS
-static
$ echo $LDFLAGS
-static -static-libgcc -static-libstdc++
$ ./configure --enable-static LDFLAGS='-static -static-libgcc -static-libstdc++' --disable-shared
...
Configuration is done.
$ make
...
Making all in unittest
...
$ file src/api/tesseract
src/api/tesseract: ELF 64-bit LSB shared object, x86-64, version 1
(GNU/Linux), dynamically linked, interpreter /lib64/l, for
GNU/Linux 3.2.0,
BuildID[sha1]=96afb1f1ff8962b3f9046c40407364ebf26369d1, with
debug_info, not stripped
Not statically linked.

Related

Setting compiler library search path not working

I built a native compiler for aarch64. The built was successful. I'm having problems though, specifying the glibc (libc.so) library to link against. I followed the suggestion in this link, about compiling with multiple glibc, but is not working.
The environment:
ARM 64bit machine.
A toolchain in toolchain_dir/bin/aarch64-linux-g++.
A sysroot directory in toolchain/sysroot/lib, which contains the lib.so.6 (glibc 2.25) and libstdc++.so (6.0.22) libraries and also the ld-linux-aarch64.so.1 linker.
The /lib64 directory contains the libc.so.6 (glibc 2.17) and libstdc++.so (6.0.19), old versions.
What I tried:
I tried to compile a simple program as:
$aarch-64-linux-g++ file.cpp -o out \
-L/home/user/toolchain/sysroot/lib -lc -lstdc++ \
-Wl,--rpath=/home/user/toolchain/sysroot/lib \
-Wl,--dynamic-link=/home/user/toolchain/sysroot/lib/ld-linux-aarch64.so.1
But I'm getting the error "/lib64/libstdc++.so.6: version GLIBCXX_3.4.20 not found". The error discloses that the rpath is not working, as is still looking into /lib64 library, instead of toolchain/sysroot/lib which contains the GLIBCXX_3.4.20 (libstdc++.so.6).
Next, I moved the toolchain/sysroot/lib/libstdc++.so.6 to /lib64, and compile again with the same command above, now getting the error: "/lib64/libstdc++.so.6 version GLIBC_2.18 not defined". The error shows the new built libstdc++.so.6 trying to find the new built glibc-2.25, but is failing as is searching in the wrong directory path in /lib64.
Next, I set the LD_LIBRARY_PATH=/home/user/toolchain/sysroot/lib. But right after setting this variable I get segmentation faults.
Do you have ideas why this is happening? How could I solve this issue? Thanks!
Edit:
Below more information from compiler, for g++ -v removed part of the output as is really long:
$aarch64-unknown-linux-gnueabi-g++ -v
Target: aarch64-unknown-linux-gnueabi
Configured with: --build=x86_64-build_pc-linux-gnu --host=aarch64-host_unknown-linux-gnueabi --target=aarch64-unknown-linux-gnueabi --enable-gold --disable-nls --disable-multilib --with-local-prefix=/home/common/userX/x-tools/HOST-aarch64-unknown-linux-gnueabi/aarch64-unknown-linux-gnueabi/aarch64-unknown-linux-gnueabi/sysroot --enable-long-long
gcc version 6.3.1 20170109 (crosstool-NG crosstool-ng-1.23.0)
$file aarch64-unknown-linux-gnueabi-g++
ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 4.10.8, stripped

Building GDAL with all libraries static

I want to develop a small program that checks which polygons from a shapefile intersect a given rectangle. This program is to be used in a website (with PHP's exec() command). The problem is, my webserver cannot install GDAL, for reasons unknown to me. So I can't link to the shared libraries. Instead, I must link to static libraries, but these aren't given.
I've downloaded the GDAL source code from here (2.3.2 Latest Stable Release - September 2018), and followed the build instructions from here. Since I already have GDAL working on my Debian, and don't want to mess with it, I followed the "Install in non-root directory" instructions, with some adjusts from the last item in the "Some caveats" section:
cd /home/rodrigo/Downloads/gdal232/gdal-2.3.2
mkdir build
./configure --prefix=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/ --without-ld-shared --disable-shared --enable-static
make
make install
export PATH=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/bin:$PATH
export LD_LIBRARY_PATH=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib:$LD_LIBRARY_PATH
export GDAL_DATA=/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/share/gdal
/usr/bin/gdalinfo --version
build/bin/gdalinfo --version
The first /usr/bin/gdalinfo --version gives 2.1.2 (the previous installed version). The second, build/bin/gdalinfo --version, gives 2.3.2 (the version just built).
By now, my program only uses the ogrsf_frmts.h header, which is in /usr/include/gdal/ or /home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/include/ directory, depending on the build. There's no ogrsf_frmts.a file, but only a libgdal.a. Is this the file I should be linking against? If so, how? I've tried so far:
gcc geofragc.cpp -l:libgdal.a
gcc geofragc.cpp -Wl,-Bstatic -l:libgdal.a
gcc geofragc.cpp -Wl,-Bstatic -l:/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp -Wl,-Bstatic -l/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp /home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp -l/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
gcc geofragc.cpp -l:/home/rodrigo/Downloads/gdal232/gdal-2.3.2/build/lib/libgdal.a
but nothing works. What am I missing?
EDIT
The second trial (gcc geofragc.cpp -Wl,-Bstatic -l:libgdal.a) is giving the following error:
/usr/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-linux-gnu/6/../../../../lib/libgdal.a(gdalclientserver.o): In function `GDALServerSpawnAsync()':
(.text+0x1f5e): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status
You can use the gdal-config program to get correct options for compilation and linking. This program is a part of the GDAL library and it has its own options:
hekto#ubuntu:~$ gdal-config --help
Usage: gdal-config [OPTIONS]
Options:
[--prefix[=DIR]]
[--libs]
[--dep-libs]
[--cflags]
[--datadir]
[--version]
[--ogr-enabled]
[--gnm-enabled]
[--formats]
You have to make sure this program is on your search path, or you can create an alias - for example:
alias gdal-config='/home/rodrigo/Downloads/gdal232/gdal-2.3.2/bin/gdal-config'
Now your compilation and linking command becomes the following one:
g++ `gdal-config --cflags` geofragc.cpp `gdal-config --libs` `gdal-config --dep-libs`
You have to use the g++ compiler to link with C++-built libraries.
Another option is to create a Makefile with these lines:
CXXFLAGS += ${shell gdal-config --cflags}
LDLIBS += ${shell gdal-config --libs}
LDLIBS += ${shell gdal-config --dep-libs}
geofragc: geofragc.cpp
and just call make with this Makefile.
I hope, it'll help.

Link whole program statically

I have an application in c++ ported from Windows to Linux, everything worked ok, but...
Our customer what that application running on Debian 3.1 (sarge), I cannot force the gcc version on the target system and I prefer to use new gcc (there are some c++11 constructs, which I'd like to preserve). I want to make executable for now for tests and .so file in future.
I decide to compile my procect statically.
when I run:
g++ -static -o prog obj/sublib1/file1.o obj/sublib1/file2.o obj/sublib2/file1.o obj/sublib2/file2.o (...) -L../somedir -s -lsomestaticlib
I get en error:
/usr/lib/gcc/i586-suse-linux/4.8/../../../../i586-suse-linux/bin/ld: cannot find -lm
/usr/lib/gcc/i586-suse-linux/4.8/../../../../i586-suse-linux/bin/ld: cannot find -lc
The system is OpenSuse 13.1 32bit, uname -a:
Linux linux-zfaz.site 3.11.6-4-desktop #1 SMP PREEMPT Wed Oct 30 18:04:56 UTC 2013 (e6d4a27) i686 i686 i386 GNU/Linux
The problem is probably with math library and C library. The dynamic version of both libraries are in /lib directory.
(probably doesn't matter: I was trying to build it using code::blocks, but when problem occurred I've moved to terminal)
Do I need to install static version of these libraries? How?
If you're using a recent version of g++, the option -static-libstdc++ should be all you need. This will ensure that the g++ libraries are linked statically, but that the system libraries (for which there usually isn't a static version) are linked dynamically. (Don't use the -static in this case.)
You need to install the glibc-devel-static package, though if applicable the answer of #jameskanze is a better option.

Linking g++ 4.8 to libstdc++

I downloaded and built gcc 4.8.1 on my desktop, running 64-bit Ubuntu 12.04. I built it out of source, like the docs recommend, and with the commands
../../gcc-4.8.1/configure --prefix=$HOME --program-suffix=-4.8
make
make -k check
make install
It seemed to pass all the tests, and I installed everything into my home directory w/ the suffix -4.8 to distinguish from the system gcc, which is version 4.6.3.
Unfortunately when I compile c++ programs using g++-4.8 it links to the system libc and libstdc++ rather than the newer ones compiled from gcc-4.8.1. I downloaded and built gcc 4.8 because I wanted to play around with the new C++11 features in the standard library, so this behaviour is definitely not what I wanted. What can I do to get gcc-4.8 to automatically link to the standard libraries that came with it rather than the system standard libraries?
When you link with your own gcc you need to add an extra run-time linker search path(s) with -Wl,-rpath,$(PREFIX)/lib64 so that at run-time it finds the shared libraries corresponding to your gcc.
I normally create a wrapper named gcc and g++ in the same directory as gcc-4.8 and g++-4.8 which I invoke instead of gcc-4.8 and g++-4.8, as prescribed in Dynamic linker is unable to find GCC libraries:
#!/bin/bash
exec ${0}SUFFIX -Wl,-rpath,PREFIX/lib64 "$#"
When installing SUFFIX and PREFIX should be replaced with what was passed to configure:
cd ${PREFIX}/bin && rm -f gcc g++ c++ gfortran
sed -e 's#PREFIX#${PREFIX}#g' -e 's#SUFFIX#${SUFFIX}#g' gcc-wrapper.sh > ${PREFIX}/bin/gcc
chmod +x ${PREFIX}/bin/gcc
cd ${PREFIX}/bin && ln gcc g++ && ln gcc c++ && ln gcc gfortran
(gcc-wrapper.sh is that bash snippet).
The above solution does not work with some versions of libtool because g++ -Wl,... -v assumes linking mode and fails with an error.
A better solution is to use specs file. Once gcc/g++ is built, invoke the following command to make gcc/g++ add -rpath to the linker command line (replace ${PREFIX}/lib64 as necessary):
g++ -dumpspecs | awk '/^\*link:/ { print; getline; print "-rpath=${PREFIX}/lib64", $0; next } { print }' > $(dirname $(g++ -print-libgcc-file-name))/specs
I just had the same problem when building gcc-4.8.2. I don't have root access on that machine and therefore need to install to my home directory. It took several attempts before I figured out the magic required to get this to work so I will reproduce it here so other people will have an easier time. These are the commands that I used to configure gcc:
prefix=/user/grc/packages
export LDFLAGS=-Wl,-rpath,$prefix/lib
export LD_RUN_PATH=$prefix/lib
export LD_LIBRARY_PATH=$prefix/lib
../../src/gmp-4.3.2/configure --prefix=$prefix
../../src/mpfr-2.4.2/configure --prefix=$prefix
../../src/mpc-0.8.1/configure --prefix=$prefix --with-mpfr=$prefix --with-gmp=$prefix
../../src/gcc-4.8.2/configure --prefix=$prefix --with-mpfr=$prefix --with-gmp=$prefix --with-mpc=$prefix --enable-languages=c,c++
That got me a working binary but any program I built with that version of g++ wouldn't run correctly unless I built it with the -Wl,-rpath,$prefix/lib64 option. It is possible to get g++ to automatically add that option by providing a specs file. If you run
strace g++ 2>&1 | grep specs
you can see which directories it checks for a specs file. In my case it was $prefix/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/specs so I ran g++ -dumpspecs to create a new specs file:
cd $prefix/lib/gcc/x86_64-unknown-linux-gnu/4.8.2
$prefix/bin/g++ -dumpspecs > xx
mv xx specs
and then edited that file to provide the -rpath option. Search for the lines like this:
*link_libgcc:
%D
and edit to add the rpath option:
*link_libgcc:
%D -rpath /user/grc/packages/lib/%M
The %M expands to either ../lib or ../lib64 depending on whether you are building a 32-bit or a 64-bit executable.
Note that when I tried this same trick on an older gcc-4.7 build it didn't work because it didn't expand the %M. For older versions you can remove the %M and just hardcode lib or lib64 but that is only a viable solution if you only ever build 32-bit executables (with lib) or only ever build 64-bit executables (with lib64).
gcc -print-search-dirs will tell you where your compiler is looking for runtime libraries, etc. You can override this with the -B<prefix> option.

Boost and Python 3.x

How does boost.python deal with Python 3? Is it Python 2 only?
Newer versions of Boost should work fine with Python V3.x. This support has been added quite some time ago, I believe after a successful Google Summer of Code project back in 2009.
The way to use Python V3 with Boost is to properly configure the build system by adding for instance:
using python : 3.1 : /your_python31_root ;
to your user-config.jam file.
libboostpython needs to be built with python3 in order to do this. This doesn't work with boost 1.58 (which comes with Ubuntu 16.04), so make sure you download the latest boost distribution. I just did this with boost_1_64_0.
As mentioned above, find the file "user-config.jam" in you boost code distribution, and copy it to $HOME.
cp /path/to/boost_1_64_0/tools/build/example/user-config.jam $HOME
Then edit the python line (the last line) so that is says:
using python : 3.5 : /usr/bin/python3 : /usr/include/python3.5m : /usr/lib ;
This is correct for Ubuntu 16.04. You can use pkg-config to find the correct include directory.
user#computer > pkg-config --cflags python3
-I/usr/include/python3.5m -I/usr/include/x86_64-linux-gnu/python3.5m
And you only need the first include directory.
Then build boost from scratch. (Sorry.) I install it to /usr/local
cd /path/to/boost_1_64_0
./bootstrap.sh --prefix=/usr/local
./b2
sudo ./b2 install
Now jump into the python example directory, and build the tutorial
cd /path/to/boost_1_64_0/libs/python/example/tutorial
bjam
This will not build correctly if you have a system install of boost, because, under the hood, bjam is linking to libboostpython using the g++ parameter "-lboost". But, on Ubuntu 16.04, this will just go and find "/usr/lib/x86_64-linux-gnu/libboost_python-py27.so.1.58.0", and then the python bindings will fail to load. In fact, you'll get his error:
ImportError: /usr/lib/x86_64-linux-gnu/libboost_python-py27.so.1.58.0: undefined symbol: PyClass_Type
If you want to see the g++ commands that bjam is using, do this:
user#computer > bjam -d2 -a | grep g++
g++ -ftemplate-depth-128 -O0 -fno-inline -Wall -g -fPIC -I/usr/include/python3.5m -c -o "hello.o" "hello.cpp"
g++ -o hello_ext.so -Wl,-h -Wl,hello_ext.so -shared -Wl,--start-group hello.o -Wl,-Bstatic -Wl,-Bdynamic -lboost_python -ldl -lpthread -lutil -Wl,--end-group
Here we see the problem, you need "-L/usr/includ/lib" just before "-lboost_python". So execute this to link the shared library correctly:
g++ -o hello_ext.so -Wl,-h -Wl,hello_ext.so -shared -Wl,--start-group hello.o -Wl,-Bstatic -Wl,-Bdynamic -L/usr/local/lib -lboost_python -ldl -lpthread -lutil -Wl,--end-group
You may need to rerun ldconfig (or reboot)
sudo ldconfig
And you are finally ready to go:
user#computer > python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello_ext
>>> hello_ext.greet()
'hello, world'
>>> exit()
Yes this question is super old, but I had to do something that wasn't specified in any of the answers here (though it was built off some of the suggestions), so I'll quickly jot down my entire process:
Download boost_X_Y_Z.tar.bz2 (I used boost 1.68.0)
tar --bzip2 -xf boost_1_68_0.tar.bz2 (where you want folder to be temporarily)
cd boost_1_68_0
./bootstrap.sh --with-python-version=3.6 --prefix=/usr/local
./b2
sudo ./bjam install
cp tools/build/example/user-config.jam $HOME, then modify the contents of this file to say using python : 3.6 : /usr/bin/python3 : /usr/include/python3.6m : /usr/lib ; (or whatever folders are appropriate for your environment)
Given this C++ source file BoostPythonHelloWorld.cpp:
#include <boost/python.hpp>
char const* say_hi()
{
return "Hi!";
}
BOOST_PYTHON_MODULE(BoostPythonHelloWorld)
{
boost::python::def("say_hi", say_hi);
}
And this Python script BoostPythonHelloWorld.py:
import BoostPythonHelloWorld
print(BoostPythonHelloWorld.say_hi())
It can be compiled and ran as such:
gcc -c -fPIC -I/path/to/boost_1_68_0 -I/usr/include/python3.6 /other_path/to/BoostPythonHelloWorld.cpp
gcc -shared -Wall -Werror -Wl,--export-dynamic BoostPythonHelloWorld.o -L/path/to/boost_1_68_0/stage/lib -lboost_python36 -o BoostPythonHelloWorld.so
python3 BoostPythonHelloWorld.py
The part that was different for me was -Wl,--export-dynamic BoostPythonHelloWorld.o, I had not seen that anywhere else, and I was getting a Python error concerning an undefined symbol until I added that.
Hope this helps someone down the line!
If you get "error: No best alternative for /python_for_extension" be sure to have
using python : 3.4 : C:\\Python34 : C:\\Python34\\include : C:\\Python34\\libs ;
only in user-config.jam in your home path and nowhere else.
Use double backslashes when compiling under windows with mingw (toolset=gcc) or MSVC (toolset=msvc).
Compile with cmd, not msys, and if you also have python 2.7 installed remove that from PATH in that shell.
First do
bootstrap.bat gcc/msvc
assuming you have the gcc/msvc tools available via PATH (/ for the alternatives, but use only one, or leave away)
Afterward you can also do
booststrap.sh --with-bjam=b2
in msys to generate a project-config.jam, but need to edit it to remove the "using python" and "/usr",..
Then the following
b2 variant=debug/shared link=static/shared toolset=gcc/msvc > b2.log
With static the python quickstart examples did not work for me, although I would prefer to do without the boost_python dll.
I did not try on linux, but it should be more straightforward there.
You can even specify the python distribution via
./bootstrap.sh --with-python=<path to your python binary>
e.g.
./bootstrap.sh --with-python=python3
for your system's python3 or
./bootstrap.sh --with-python=$VIRTUAL_ENV/bin/python
for the python version of your currently active virtual env python.
Refer this to know how to build boost with python. It shows the way to build with python2 with Visual Studio 10.0 (2010). But I go through the same procedure for a project that I am currently working on and it works fine with python 3.5 and Visual Studio 14.1 (2017).
If you get this error when building your python boost project, just add BOOST_ALL_NO_LIB value to Preprocessor Definitions (inside C\C++ > preprocessor tab) in your project properties.
And also, do not forget to add boost .dll files location to your system path.
When the path to Python contains spaces, you will be in for quite a ride. After a whole lot of trial and error, I finally managed to get something that works. Behold my user-config.jam (which has to be in my home directory for bjam to find it):
import toolset : using ;
using python : 3.6
: \"C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\\Shared\\Python36_64\\python.exe\"
: C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\\Shared\\Python36_64\\include
: C:\\Program\ Files\ (x86)\\Microsoft\ Visual\ Studio\\Shared\\Python36_64\\libs
;
The inconsistent quoting is intended and seems to be required. With this I can build boost-python and use it as Boost::python36 in my CMakeLists.txt. Still, one issue remains: I have to link to python manually viz
target_link_libraries(MyTarget
Boost::boost Boost::python36
"C:/Program Files (x86)/Microsoft Visual Studio/Shared/Python36_64/libs/python36.lib")
target_include_directories(MyTarget PRIVATE
"C:/Program Files (x86)/Microsoft Visual Studio/Shared/Python36_64/include")
In my case adding "Using Python : 3 etc." into user-config.jam in my home directory didn't work. I had to add the line into project-config.jam instead, which resides in the root directory of unpacked boost.
Specifically the line was:
using python : 3.9 : /usr/bin/python3 : /usr/include/python3.9 : /usr/lib ;
and the version of boost was 1_78_0