How to link my app statically against ICU 57.1 MinGW - c++

I've built ICU 57.1 statically with MinGW x32;
As a result, I got the following files in the lib directory:
libsicudt.a
libsicuin.a
libsicuio.a
libsicule.a
libsiculx.a
libsicutest.a
libsicutu.a
libsicuuc.a
sicudt.a
sicudt.dll
Now I want to run one of the examples, but whatever I try it
I receive errors like
"undefined reference to unum_...
unum_setAttribute
unum_formatInt64
u_isspace".
Total number of errors at the beginning was about 1700.
Analyzing pkgconfig files I figured out some mutual dependencies and
after reordering .a files in cmd line reduced errors to 82.
But I have no idea where to go next.
Google shows that many people have same problem with ICU but
so far there is no solution that works for me and explains the cause.
When building, I use Qt Creator for convenience, here is my .pro file:
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp
ICUDIR=$$(ICU_PATH)
ICU_LIBPATH=$$ICUDIR"/dist/lib/"
INCLUDEPATH += $$ICUDIR"/dist/include"
LIBS += $$ICU_LIBPATH"libsicuuc.a" $$ICU_LIBPATH"libsicudt.a" \
$$ICU_LIBPATH"libsicuin.a" $$ICU_LIBPATH"libsicuio.a" \
$$ICU_LIBPATH"libsicule.a" $$ICU_LIBPATH"libsiculx.a" \
$$ICU_LIBPATH"libsicutu.a" $$ICU_LIBPATH"sicudt.a"
I have following questions:
1) Can anybody write a simple one line command that statically builds
the simpliest ICU app using g++? Is it even possible?
2) What is the correct order of .a files when passing them to linker?
3) What are files libsicudt.a, sicudt.a and sicudt.dll inteded for?
4) Is the file list I wrote above complete or my build is corrupt?
5) Is there anything I've missed of doing wrong?

Finally, I solved the problem. In order to share my experiece with you
I will describe four major pitfalls that I've encountered.
I assume that you use msys2 and MinGW-w32 if you want to repeat the steps.
Use same toolchain for everything. Note that MinGW, MinGW-w32 and MinGW-w64
are 3 different toolchains. If you have multiple installations of MinGW
like me, make sure that you use only one of them for the entire project.
I chose MinGW-w32 for compatibility reasons.
The newest versions of software often contain bugs, and they
require from you some more dancing with tambourins.
ICU v58 was buggy at the moment of writing this post.
The solution is to revert to an older version (57.1 in my case).
Before building ICU library, make sure to setup everything correctly.
Here problem is with using namespaces and renaming namespaces which
ICU does by default.
Find file C:\icu\source\common\unicode\uconfig.h and add the following
at the beginning after include guards:
#define U_DISABLE_RENAMING 1
#define U_USING_ICU_NAMESPACE 0
Save the file. Open MSYS2 terminal and set mingw-w32 as working toolset:
export PATH="/c/msys64/mingw32/bin:$PATH"
Go to icu/source dir:
cd /c/icu/source
Configure ICU for static build with no renaming and U_USING_ICU_NAMESPACE=0:
export CFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_GNUC_UTF16_STRING=1 -DU_STATIC_IMPLEMENTATION"
export CXXFLAGS="-DU_USING_ICU_NAMESPACE=0 -std=gnu++11 -DU_CHARSET_IS_UTF8=1 -DU_GNUC_UTF16_STRING=1 -DU_HAVE_CHAR16_T=1 -DUCHAR_TYPE=char16_t -Wall --std=c++11 -DU_STATIC_IMPLEMENTATION" -static-libstdc++ -fno-exceptions
export CPPFLAGS="-DU_DISABLE_RENAMING=1 -DU_CHARSET_IS_UTF8=1 -DU_STATIC_IMPLEMENTATION"
export LDFLAGS="-std=gnu++11"
./runConfigureICU MinGW prefix=$PWD/../dist -enable-static -disable-shared --disable-renaming
Build and install ICU lib. -j4 speeds up the process if you have 4 cores:
mingw32-make -j4
mingw32-make install
Cleanup intermediate files:
mingw32-make clean
Now you should have static libraries located at icu/dist/lib .
PITFALL 4: when linking statically, you should pass libraries to
linker in correct order. That matters only for static linking.
But how to figure out which order is correct?
Here pkg-config tool comes handy.
What it does is the following: takes library package names as
parameter, calculates dependencies and returns the complete string
of parameters that can be fed directly to the compiler
or viewed by you to understand what's going on under the hood.
There are 5 packages located at C:\icu\dist\lib\pkgconfig.
Let's configure path for pkg-config:
export PKG_CONFIG_PATH="/c/icu/dist/lib/pkgconfig:$PKG_CONFIG_PATH"
In order to test it, type:
pkg-config --static --cflags --libs icu-uc icu-i18n icu-io icu-le icu-lx
The output should be:
-IC:/icu/dist/include -LC:/icu/dist/lib -lsicuio -lsicuin -lsiculx -lsicule -lsicuuc -lsicudt -lpthread -lm
That's the string we have to pass to compiler.
As final test, we will compile a simple example app using command line:
Create folder /c/icu/dist/test with file test.cpp inside:
#include <unicode/unistr.h>
#include <unicode/ustdio.h>
#include <unicode/brkiter.h>
#include <stdlib.h>
using namespace icu;
void printUnicodeString(UFILE *out, const UnicodeString &s) {
UnicodeString other = s;
u_fprintf(out, "\"%S\"", other.getTerminatedBuffer());
}
int main( void )
{
UFILE *out;
UErrorCode status = U_ZERO_ERROR;
out = u_finit(stdout, NULL, NULL);
if(!out) {
fprintf(stderr, "Could not initialize (finit()) over stdout! \n");
return 1;
}
ucnv_setFromUCallBack(u_fgetConverter(out), UCNV_FROM_U_CALLBACK_ESCAPE,
NULL, NULL, NULL, &status);
if(U_FAILURE(status)) {
u_fprintf(out, "Warning- couldn't set the substitute callback - err %s\n", u_errorName(status));
}
/* End Demo boilerplate */
u_fprintf(out,"ICU Case Mapping Sample Program\n\n");
u_fprintf(out, "C++ Case Mapping\n\n");
UnicodeString string("This is a test");
u_fprintf(out, "\nstring: ");
printUnicodeString(out, string);
string.toUpper(); /* string = "THIS IS A TEST" */
u_fprintf(out, "\ntoUpper(): ");
printUnicodeString(out, string);
return 0;
}
Go to the test dir:
cd /c/icu/dist/test
g++ -o test test.cpp \
`pkg-config --cflags --libs --static icu-uc icu-i18n icu-io icu-le icu-lx`
Run the app:
./test
Maybe this is not the best way to do,
especially concerning workspaces, but it works.
More about pgk-config here:
https://people.freedesktop.org/~dbn/pkg-config-guide.html

Related

Can't compile with mingw linking a library on Linux to create executable for Windows

I'm trying to compile C/C++ code from my Debian partition to generate some executable files for Windows.
Running $ uname -a on the command line gives Linux machine 5.14.0-2-amd64 #1 SMP Debian 5.14.9-2 (2021-10-03) x86_64 GNU/Linux. My processor is an Intel® Core™ i5-1035G4 CPU # 1.10GHz × 8, with a Mesa Intel® Iris(R) Plus Graphics (ICL GT1.5) integrated GPU.
A minimal example to show my current situation includes the following code (called code.cpp):
#include <iostream>
#include <CL/opencl.hpp>
int main()
{
std::vector <cl::Platform> all_platforms; //Get all platforms
cl::Platform::get(&all_platforms);
if (all_platforms.size() == 0)
{
std::cout << "No platforms found. Check OpenCL installation." << std::endl;
exit(1);
}
int pz = all_platforms.size();
std::cout << "Platforms size: " << pz << std::endl;
for (int i = 0; i < pz; i++)
{
cl::Platform default_platform = all_platforms[i];
std::cout << "Using platform: " << default_platform.getInfo<CL_PLATFORM_NAME>() << std::endl;
}
return(0);
}
which uses OpenCL to print all recognized devices. I compile my code writing g++ code.cpp -o code.out -lOpenCL. The executable file code.out works fine, doing what you would expect it to do. I have another program which uses GSL (GNU Scientific Library) written in C which also works well, linking with -lgsl (therefore I think there's not a problem with my code or the regular compilation process). Both OpenCL and GSL were installed from the official repositories (~# apt install ...) with no problem at all. When I execute code.out the output is
Platforms size: 2
Using platform: Intel(R) OpenCL HD Graphics
Using platform: Portable Computing Language
I installed mingw (via ~# apt install mingw-w64) to create executable files to be run on Windows, and for basic programs (i.e. without "external" libraries) it works well (replacing gcc by x86_64-w64-mingw32-gcc or i686-w64-mingw32-gcc). However for the code written above (and for the one using GSL) it doesn't work. Most of the error outputs are very similar for both examples, and I will show the command line outputs for the code using OpenCL.
When I try x86_64-w64-mingw32-g++ code.cpp -o code.out -lOpenCL the output is
code.cpp:2:10: fatal error: CL/opencl.hpp: No such file or directory
2 | #include <CL/opencl.hpp>
| ^~~~~~~~~~~~~~~
compilation terminated.
I thought this meant that I needed to be more specific when linking and including, so I gave the explicit path where the headers are located (found them via dpkg -S opencl.hpp or dpkg -S gsl*.h), and the .so file for OpenCL was found via dpkg -S *OpenCL.so, while the one for GSL was found using dpkg -S *gsl.so. When I try x86_64-w64-mingw32-g++ code.cpp -o code.out -I/usr/include/ -L/usr/lib/x86_64-linux-gnu/libOpenCL.so the output is
In file included from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/cwchar:44,
from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/bits/postypes.h:40,
from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/iosfwd:40,
from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/ios:38,
from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/ostream:38,
from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/c++/iostream:39,
from code.cpp:1:
/usr/include/wchar.h:27:10: fatal error: bits/libc-header-start.h: No such file or directory
27 | #include <bits/libc-header-start.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Therefore it seems that MinGW needs additional instructions to properly find, include and/or link the libraries. I don't know how to solve this problem. Those are my attempts based on some answers I've found, and the documentation provided by MinGW says nothing about this. The exact same problem occurs no matter if I use x86_64-w64-mingw32-g++ or i686-w64-mingw32-g++, or their gcc counterparts.
When cross-compiling make sure you are only linking things targeting the same platform together. In other words, your dependencies (and their dependencies) must be for the same target platform. You can't link with those libraries for your build platform.
So if you have a Windows 64-bit application that depends on OpenCL, you will need to link it against a Windows 64-bit build of OpenCL.
The OpenCL the sources can be found here:
https://github.com/KhronosGroup/OpenCL-Headers
https://github.com/KhronosGroup/OpenCL-ICD-Loader
so you would need to build those first.

Cygwin libzint(zint) goes into infinite loop

Cygwin Zint(libzint) stucks on ZBarcode_Create() function call with basic example code which perfectly works on Linux system:
#include <zint.h>
int main()
{
struct zint_symbol *my_symbol;my_symbol = ZBarcode_Create();
if(my_symbol != NULL)
{
printf("Symbol successfully created!\n");
}
ZBarcode_Delete(my_symbol);
return 0;
}
Steps to reproduce:
Downloaded and installed Cygwin, zlib, libpng and libzint(zint) packages
In Visual Studio created a new project, added Include Path, added libzint.a library name, added library path in Linker options
Added Cygwin path to PATH variable
Tried to build libzint by myself result is the same
Can someone help me to find out is it common behavior for libs that were created with Cygwin or is it only Zint(libzint)?
The code is working fine. After installing the needed libraries with cygwin setup and
checking their presence
$ cygcheck -cd |grep zint
libzint-devel 2.4.3-3
libzint2.4 2.4.3-3
zint 2.4.3-3
the compilation is without any problem and the testing also
$ gcc -o prova prova.c -Wall -lzint
$ ./prova.exe
Symbol successfully created!

No such file or directory "ruby/config.h" when trying to compile C++ into Ruby using SWIG

I'm trying to get a basic example running using SWIG to convert a C++ file into Ruby. I have Ruby 2.0.0p451 (64 bit version) installed and I've also installed the 64-bit DevKit. I'm running Windows 7 and trying to use swigwin-2.0.12. Finally, I am using the GCC C++ compiler supplied by Mingw-builds for the 64-bit version of Windows.
I have the basic C++ hello world program as shown below.
#include <iostream>
#include <cstdlib>
using namespace std;
main()
{
cout << "Hello World!";
system("pause");
return 0;
}
At the command prompt, I use the command:
swig -module -c++ -ruby hello_world.cpp
This completes fine and produces a file titled hello_world_wrap.cxx. However, when I receive an error when I try to compile the .cxx file using the command:
g++ -fPIC -c hello_world_wrap.cxx -IC:\Ruby200-x64\include\ruby-2.0.0
The error I am receiving is:
All the research I've done has pointed me to an installation of the incorrect DevKit, but I don't think this is my issue. I've made sure to download the 64-bit version of Ruby and the DevKit. I've checked the folder specified in the error, and there is no config.h file. I'm not sure why the config.h file does not exist or why ruby.h is trying to load it.
Any thoughts?
Check that C:\Ruby200-x64\include\ruby-2.0.0\ruby\config.h exists. If not, find it and fix the path.
Update:
Check if there is a ruby.h in the same folder. If there is then just use -IC:\Ruby200-x64\include\ruby-2.0.0\ruby\x64-mingw instead. Otherwise try adding a second -I, for this extra path. I agree with you this is a little strange (not so much the former, but definitely if you have to have two -I). The script at https://groups.google.com/forum/m/#!topic/comp.lang.ruby/RpjuvXpFI30 suggests that this might be normal, I.e. you need one -I for platform-independent headers and one for platform-dependent.

Error when running OpenNI 2 class ( gcc 4.7.2 / ubuntu 12.10 )

I'm trying to compile an run a very basic program given below (test.cpp) which calls the OpenNI class. You can see the files and dirs they're in here. Sorry that some characters screws up a little bit in the browser's encoding. I'm using the linux command: tree, if you know a better command tell me and I will update it.
File Structure
I'm following the guide here, see "GCC / GNU Make".
#include < stdio.h >
#include < OpenNI.h >
using namespace openni;
int
main ( void )
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("\nInitialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
printf("Hello, world!\n");
return 0;
}
Here is what I'm running in the command line to compile it (gcc 4.7.2):
gcc test.cpp -I../OpenNI-2.0.0/Include -L/home/evan/Code/OpenNi/Init -l OpenNI2 -o test
This works fine but when I run ./test I get the following error:
Initialize failed
DeviceDriver: library handle is invalid for file libOniFile.so
Couldn't understand file 'libOniFile.so' as a device driver
DeviceDriver: library handle is invalid for file libPS1080.so
Couldn't understand file 'libPS1080.so' as a device driver
Found no valid drivers in './OpenNI2/Drivers'
Thanks, any help would be much appreciated.
Instructions from your guide says, that
It is highly suggested to also add the "-Wl,-rpath ./" to your linkage command. Otherwise, the runtime linker will not find the libOpenNI.so file when you run your application. (default Linux behavior is to look for shared objects only in /lib and /usr/lib).
It seems you have exactly this problem -- it can not find some libraries. Try to add proper rpath (seems to be /home/evan/Code/OpenNi/Init/OpenNI2/Drivers in your case) to your compilation string.
I had the same issue after compiling this little "Hello World" with Eclipse and trying to run it in the command line.
The "Wl,-rpath=./" thing did not work for me.
As also discussed here it worked for me after setting some env. variables before execution:
export LD_LIBRARY_PATH="/path/to/OpenNI2:$LD_LIBRARY_PATH"
export OPENNI2_DRIVERS_PATH="/path/to/OpenNI2/Drivers"
export LD_LIBRARY_PATH="/path/to/OpenNI2/Drivers:$LD_LIBRARY_PATH"
Somewhere I got the info that the first two lines should be enough but it was the third line which is important. I does also work just with the third line.

Using ofstream on AIX

I am trying to write a simple C++ program on an AIX Box.
The program is given below:
# include <iostream>
# include <fstream>
using namespace std ;
int main()
{
ofstream of ;
of.open("license.txt") ;
of<<"hello"<<endl ;
of.close() ;
}
My LDFLAGS has is set as following:
-maix64 -L/disk3/TOOLS/GCCTools/gcc-4.5.1/lib/ppc64 \
-L/disk3/TOOLS/GCCTools/gcc-4.5.1/lib/gcc/powerpc-ibm-aix6.1.0.0/4.5.1/ppc64 \
-L/disk3/TOOLS/GCCTools/gcc-4.5.1/lib/gcc/powerpc-ibm-aix6.1.0.0/4.5.1 \
-L/disk3/TOOLS/OPENSSL/lib
CFLAGS is:
-O2 -maix64 -I/disk3/TOOLS/OPENSSL/include -D_ALL_SOURCE -D_XOPEN_SOURCE \
-D_XOPEN_SOURCE_EXTENDED -DSS_64BIT_SERVER -D_POSIX_SOURCE -D__64BIT__ \
-I/disk3/TOOLS/OPENSSL/include -I/usr/include \
-I/disk3/TOOLS/GCCTools/gcc-4.5.1/lib/gcc/powerpc-ibm-aix6.1.0.0/4.5.1/include
The program compiles fine. But when I try to run the same, the program comes out with a segmentation fault.
I ran the same with gdb and found the following issue when I use ofstream:
Program received signal SIGSEGV, Segmentation fault.
0x09000000036107c4 in std::locale::operator=(std::locale const&) (this=
findvar.c:706: internal-error: value_from_register: Value not stored anywhere!
Any idea on why this is happening?
Any help is appreciated :)
Note: fstream in itself works...
I meet the same error. The key points to repro the error are:
1 use std::stream(such as std::ofstream) in share libary;
2 use pthread function (such as pthread_self) in share library;
3 use "-O2" to optimize code.
Then it shows "Segmentation fault (core dumped)".
AIX provides 2 versions(64bit) of libstdc++.a. (see http://www.perzl.org/aix/index.php?n=Main.GCCBinariesVersionNeutral)
64-bit compilation, non-thread-safe (<prefix>/ppc64)
64-bit compilation, thread-safe (<prefix>/pthread/ppc64)
My solution is:
change LIBPATH to use "<prefix>/pthread/ppc64" version.
such as set LIBPATH as "/opt/freeware/lib/gcc/powerpc-ibm-aix6.1.0.0/4.6.1/pthread/ppc64/"
It works well in my machine.
It's been a while, but out of my head: don't you need to add -pthread to the compile / link options?
I have analyzed the issue and found a work around.
Here is what i did:
I did an ldd on my testprog executable:
ldd test
test needs:
/usr/lib/threads/libc.a(shr_64.o)
/disk3/TOOLS/GCCTools/gcc-4.5.1/lib/gcc/powerpc-ibm-aix6.1.0.0/4.5.1/pthread/ppc64/libstdc++.a(libstdc++.so.6)
/disk3/TOOLS/GCCTools/gcc-4.5.1/lib/gcc/powerpc-ibm-aix6.1.0.0/4.5.1/pthread/ppc64/libgcc_s.a(shr.o)
/unix
/lib/libcrypt.a(shr_64.o)
/lib/libpthreads.a(shr_xpg5_64.o)
I found that pthread's libstdc was being used. This was due to my LIBPATH having this path before /usr
Next, I reset my LIBPATH to exclude all those paths which had pthread's gcc being used, making sure that the other gcc libraries used where available in LIBPATH
Finally I compiled the test program with this new LIBPATH
Note: LD_LIBRARY_PATH is used by linux and LIBPATH is used by AIX.
Cheers!