I'm using autotools as build system for a library of mine. Recently library is ported to Windows. Library compiles and links successfully though I encountered a strange error. There is only static libraries after configure and make. Evertything looks OK except a warning from libtool:
libtool: undefined symbols not allowed in i686-pc-mingw32 shared
I have exported all symbols for Windows machines by this code:
#ifdef _WIN32
# ifdef DLL_EXPORT
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#endif
#ifndef _WIN32
# define LIBRARY_API
#endif
And in every single definition I have:
class LIBRARY_API myClass {
// ...
Notes:
Operating System: Windows 8 x86_64
Compiler suite: MinGW x86_64, MSYS x86
In your configure.ac, make sure your libtool initialization looks like:
LT_INIT([win32-dll])
Also, you need to pass -no-undefined flag to libtool in your Makefile.am. This flag disables the warning you are getting:
libexample_la_LDFLAGS = -no-undefined
More details about this in the LT_INIT documentation.
Related
My library is built with some #define enabled (e.g -DUSE_FOO=1) and also USE_FOO is used in public header file.
The problem is an application using library includes the public header file and thus USE_FOO appears in the application context and would be undefined in application context.
How can I export USE_FOO define to application based on whether it's enabled in the library or not?
e.g
include/public/foo.h
lib/libfoo.so --> foo.cc
in foo.h contain code as
#if defined (USE_FOO)
#define SIZE 5
#else
#define SIZE 10
#endif
foo.cc
#include "foo.h"
int getSizeFromLib()
{
return SIZE;
}
libfoo.so source file includes foo.h and built by configuring USE_FOO at compile time.
Now, application uses libfoo library by including public/foo.h and uses his own build configuration to build the app. but the problem is application is unaware of USE_FOO which will be always undefined in application side. So SIZE will be 10 in application but 5 inside the library
I want USE_FOO to exported to application based on whether its defined for libfoo.so or not. I.e if libfoo.so is built with USE_FOO=1 application should also see USE_FOO=1 and vice-versa
If it's not possible to do it in pre-defined way, then any trick to solve this would be welcomed.
In Linux world this task is solved by pkgconfig tool. Basically in addition to binaries and headers your library also comes with a .pc file which looks like
prefix=/usr/local
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib
Name: foo
Description: The foo library
Version: 1.0.0
Cflags: -I${includedir}/foo USE_FOO=1
Libs: -L${libdir} -lfoo
This file is installed to /usr/lib/pkgconfig and clients should query proper CFLAGS from it by calling pkg-config from Makefile:
CFLAGS = -g -Wall -Wextra $(pkg-config --cflags)
For more details, check the guide.
The only portable solution would be to add an auto-generated foo-config.h header which will be included by all library public headers and would define all version-specific defines (like USE_FOO). This would of course only work in source files that actually include library headers.
There is no way to "export" a preprocessor define from a library to an application. Both must be compiled with compatible flags, for example:
CFLAGS=-DUSE_FOO=1
gcc $CFLAGS --shared -o lib/libfoo.so foo.cc
gcc $CFLAGS lib/libfoo.so app.c
The point of this effort is to prevent me from dual booting windows ,having to install CPLEX twice in the same system (storage is quite limited) and ofc be able to compile the required cross-platform executables from my main os which is debian linux.
For this reason i'm using mingw64 and my compilation script looks like this:
#!/bin/sh
#COMPILATION FLAGS
FLAGS='-DIL_STD -DILOUSEMT -D_REENTRANT'
EXTRA='-std=c++11 -static -static-libgcc -static-libstdc++'
#INCLUDES
OPL_INCL='-I/opt/ibm/ILOG/CPLEX_Studio128/opl/include'
CPL_INCL='-I/opt/ibm/ILOG/CPLEX_Studio128/cplex/include'
CON_INCL='-I/opt/ibm/ILOG/CPLEX_Studio128/concert/include'
#LINKER
OPL_LIB='-L/opt/ibm/ILOG/CPLEX_Studio128/opl/lib/x64_windows_vs2017/stat_mda'
CPL_LIB='-L/opt/ibm/ILOG/CPLEX_Studio128/cplex/lib/x64_windows_vs2017/stat_mda'
CON_LIB='-L/opt/ibm/ILOG/CPLEX_Studio128/concert/lib/x64_windows_vs2017/stat_mda'
#echo $FLAGS
/usr/bin/x86_64-w64-mingw32-g++ $FLAGS $OPL_INCL $EXTRA main.cpp $OPL_LIB $CON_LIB $CPL_LIB -lcplex -lm -lpthread
#g++ -std=c++11 $FLAGS $OPL_INCL main.cpp $OPL_LIB $CON_LIB $CPL_LIB -lcplex -lm -lpthread
What I have done is that I copied the windows version of the library files from another windows installation, and I'm now trying to compile my code using the global (I suppose) include files but using the windows version (.lib) of the necessary cplex libraries.
I thought that the nightmare would be the linking, but to my surprise, I didn't even manage to get there. The Mingw compiler is aborting compilation because of a generic.h file missing (which from what I understand with a bit of searching, it should be related with the kernel or something)
In file included from /opt/ibm/ILOG/CPLEX_Studio128/opl/include/ilconcert/iloenv.h:21:0,
from /opt/ibm/ILOG/CPLEX_Studio128/opl/include/ilconcert/iloalg.h:21,
from /opt/ibm/ILOG/CPLEX_Studio128/opl/include/ilconcert/ilomodel.h:21,
from /opt/ibm/ILOG/CPLEX_Studio128/opl/include/ilcplex/ilocplex.h:27,
from /opt/ibm/ILOG/CPLEX_Studio128/opl/include/ilopl/iloopl.h:23,
from main.cpp:3:
/opt/ibm/ILOG/CPLEX_Studio128/opl/include/ilconcert/ilosys.h:262:21: fatal error: generic.h: No such file or directory
#include "generic.h"
^
compilation terminated.
I also tried just for testing to compile using g++ and this error was quickly bypassed and as expected the new errors are related with linking the cplex library : /usr/bin/ld: cannot find -lcplex, which is probably missing cause I have not included the linux library folders.
Do I have any hopes to do that or is this impossible in the first place?
PS: I have a much simpler piece of code where I'm doing exactly the same thing (no CPLEX) involved and compilation works like a charm. So I suppose that the issue should be also CPLEX related.
The short answer is no; you probably don't have any hope of getting this to work.
In ilosys.h at line 262, we see the following:
#if !(defined(name2))
# if defined(ILO_MSVC) || defined(ILO_LINUX) || defined(ILO_APPLE) || defined(ILO_HP11)
# undef name2
# define name2(a,b) _name2_aux(a,b)
# define _name2_aux(a,b) a##b
# else
#include "generic.h"
# endif
#endif
The suspicious part is that ILO_MSVC is not defined and this is why generic.h is being included. If we go to ilosys.h at line 11, we see:
#if defined(_MSC_VER)
# undef _Windows
# define _Windows
# undef _WINDOWS
# define _WINDOWS
# undef ILO_WINDOWS
# define ILO_WINDOWS
# undef ILO_MSVC
# define ILO_MSVC
#include <stddef.h>
# if defined(_WIN64)
# undef ILO64
# define ILO64
# undef ILO_WIN64
# define ILO_WIN64
# else
# undef ILO_WIN32
# define ILO_WIN32
# endif
//# if defined(ILO_MSVC8)
//# undef _WIN32_WINNT
//# define _WIN32_WINNT 0x0400
//# endif
#endif
So, ILO_MSVC is only defined if _MSC_VER is defined. And, _MSC_VER is only defined if you have a Microsoft Visual C++ compiler installed (e.g., see here).
Finally, if you look at the detailed system requirements for CPLEX and Windows, it's pretty clear that Microsoft Visual Studio 2015 or 2017 is required.
I am building a CMake-based project for Android, using NDK r10e, x86_64, toolchain name is arm-linux-androideabi-clang3.5
Currently I'm getting very strange errors, suggesting that some Windows preprocessor macros come out, like _WIN32, _WIN64, __MINGW32__.
My project uses parts of stlplus3, version 3-03-11, particularly, filesystem
I use CMake Android toolchain from https://github.com/taka-no-me/android-cmake (this toolchain is used in OpenCV)
Here is CMake call
set ANDROID_SDK=C:\Android\sdk
set ANDROID_NDK=c:\Android\android-ndk-r10e
set ANDROID_EXECUTABLE=%ANDROID_SDK%\tools\android.bat
set CMAKE_PATH=C:\Program Files (x86)\CMake\bin
set PATH=%PATH%;%CMAKE_PATH%
cmake .. -DCMAKE_TOOLCHAIN_FILE="%~dp0\..\cmake\android.toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DANDROID_NDK=%ANDROID_NDK%^
-DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-clang3.5 -DANDROID_EXTRA_NDK_VERSIONS="-r10e"^
-DANDROID_ABI="armeabi-v7a with NEON"^
-G"Ninja"
Here is the compiler output:
[29/186] Building CXX object modules/3rdparty/stlplus3/CMakeFiles/stlplus3.dir/portability_fixes.cpp.o
FAILED: C:\Android\android-ndk-r10e\toolchains\llvm-3.5\prebuilt\windows-x86_64\bin\clang++.exe -DANDROID -D_CRT_SECURE_NO_WARNINGS -D__STDC_LIMIT_MACROS
-isystem C:/Android/android-ndk-r10e/platforms/android-8/arch-arm/usr/include -isystem C:/Android/android-ndk-r10e/sources/cxx-stl/gnu-libstdc++/4.8/include -isystem C:/Android/android-ndk-r10e/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include -isystem C:/Android/android-ndk-r10e/sources/cxx-stl/gnu-libstdc++/4.8/include/backward
-IC:/opencv/android-clang/sdk/native/jni/include/opencv -IC:/opencv/android-clang/sdk/native/jni/include -I../modules/common
-fPIC -fPIE -flax-vector-conversions -Ofast -MMD -MT
modules/3rdparty/stlplus3/CMakeFiles/stlplus3.dir/portability_fixes.cpp.o -MF
modules/3rdparty/stlplus3/CMakeFiles/stlplus3.dir/portability_fixes.cpp.o.d -o modules/3rdparty/stlplus3/CMakeFiles/stlplus3.dir/portability_fixes.cpp.o
-c ../modules/3rdparty/stlplus3/portability_fixes.cpp
../modules/3rdparty/stlplus3/portability_fixes.cpp:12:10: fatal error: 'windows.h' file not found
#include "windows.h"
Here is the respective code from portability_fixes.hpp
#if defined(_WIN32) || defined(_WIN64) || defined(_WIN32_WCE)
#define MSWINDOWS
#endif
Here is the respective code from portability_fixes.cpp
#include "portability_fixes.hpp"
#ifdef MSWINDOWS
#include "windows.h"
#endif
I have also tried adding code like th following
#if defined(_WIN32) && defined(ANDROID)
#error win32
#endif
#if defined(_WIN64) && defined(ANDROID)
#error win64
#endif
#if defined(_WIN32_WCE) && defined(ANDROID)
#error win32_wce
#endif
And have got two error messages, "win32" and "win64".
I have also tried to work around these macros, adding ... && !defined(ANDROID). But then I've got an liker error about undefined symbol __mingw_aligned_malloc in file mm_malloc.h
Studying its code, I've found the following:
static __inline__ void *__attribute__((__always_inline__, __nodebug__,
__malloc__))
_mm_malloc(size_t __size, size_t __align)
....
void *__mallocedMemory;
#if defined(__MINGW32__)
__mallocedMemory = __mingw_aligned_malloc(__size, __align);
#elif defined(_WIN32)
__mallocedMemory = _aligned_malloc(__size, __align);
#elif defined(__ANDROID__)
__mallocedMemory = memalign(__align, __size);
#else
....
So, it looks like I'm doing something wrong, but don't understand what.
Switching compiler is not an option, because of compatibility issues with other projects.
So how do I make the compiler to undefine these macros?
Also, OpenCV builds fine with the same options.
Update: I've downloaded x86 version of NDK r10e and it has compiled my code fine.
Looks like bugs in 64-bit build of NDK r10e.
I've downloaded x86 version of NDK r10e and it has compiled my code fine.
I think this is part of the problem at No type named 'unique_ptr' in namespace 'std' when compiling under LLVM/Clang. According to Marshall Clow, I can detect -stdlib=libc++ via _LIBCPP_VERSION:
If you're writing cross-platform code, sometimes you need to know what
standard library you are using. In theory, they should all offer
equivalent functionality, but that's just theory. Sometimes you just
need to know. The best way to check for libc++ is to look for the
preprocessor symbol _LIBCPP_VERSION. If that's defined, then you're
using libc++.
#ifdef _LIBCPP_VERSION
// libc++ specific code here
#else
// generic code here
#endif
Unfortunately, that breaks down with Apple's Clang (3.4-SVN) and the Clang (3.6) I built from sources after downloading from the LLVM project. I'm guessing the test is only valid under Xcode.
How can I reliably detect -stdlib=libc++ in the preprocessor?
Here is the test case:
$ cat test-clapple.cxx
// Need to test {C++03,C++11} x {libc++, no libc++}
// c++ -c test-clapple.cxx
// - OK
// c++ -stdlib=libc++ -c test-clapple.cxx
// - OK
// c++ -std=c++11 -c test-clapple.cxx
// - FAILS, no type named 'unique_ptr' in namespace 'std'
// c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx
// - OK
#include <ciso646>
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1600)
# pragma message "C++11"
#elif (__cplusplus >= 199711L)
# pragma message "C++03"
#endif
#if (_LIBCPP_VERSION)
# pragma message "libc++"
#else
# pragma message "no libc++"
#endif
#if defined(__apple_build_version__)
# pragma message "Apple build"
#else
# pragma message "non-Apple build"
#endif
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1600) // C++11
# include <memory>
#else
# include <tr1/memory>
#endif
// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1600)
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif // C++11
int main(int argc, char* argv[])
{
return argc;
}
This project does not use Autotools, Cmake, Boost, or other external libraries or frameworks.
The only effect -stdlib=libc++ has on the preprocessor is to change the include paths it uses to find standard library headers, so you can't detect the presence of -stdlib=libc++ on the command-line per se, you can only detect which standard library headers get included. Obviously you can't detect that without actually including one or more standard library headers.
If you include any libc++ header then _LIBCPP_VERSION will be defined, so the way to detect -stdlib=libc++ is to include at least one C++ library header and check for _LIBCPP_VERSION.
In C++20 and later, it is recommend to #include <version>, which was created specifically for this purpose. Prior to C++20, it is recommended to #include <ciso646> which serves no purpose in C++ and declares nothing, but for libc++ does define the _LIBCPP_VERSION macro. However, for libstdc++ historically <ciso646> did not define any macros such as __GLIBCXX__ that can be used to detect libstdc++. That changed with GCC 6.1 so <ciso646> can be used now, but for older releases you need to include a different header to detect libstdc++.
I am using gcc 4.8 installed via MacPorts, and old C++11 code would not compile anymore
if I use the compiler without the -std=c++11 flag, it works just fine with this test code
#include <cctype>
int main() {
std::isalnum('c');
return 0;
}
[bash] g++48 test.cpp
But after the Mavericks upgrade I get the following compile error:
[bash] g++48 -std=c++11 test.cpp
Undefined symbols for architecture x86_64:
"isalnum(int)", referenced from:
_main in ccvsKeqJ.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
Does anyone have a clue what might cause this issue?
I appreciate any help
OSX Mavericks upgrade will wipe out a number of XCode installation directories. In order to restore them, you need to reinstall the XCode command-line tools.
xcode-select --install
Then agree to the download prompt.
If this fails, you can try and install by hand from here: OSX: Xcode Downloads
This doesn't relate to mis-installed osx cmdline tools, but, as clearly explained in this SO question, to some inline-related macros changed in 10.9 SDK headers, in particular in usr/include/sys/cdefs.h.
As a quick workaround, you can leverage GCC's "fixed include" mechanisms and provide a slightly tweaked version of /usr/include/sys/cdefs.h that prevents the problem when compiling c++ code as follows:
Find where your installed GCC is, I'll use GCCROOT
mdkir $GCCROOT/lib/gcc/x86_64-apple-darwinXXX/4.X.Y/include-fixed/sys (where darwinXXX depends on where you compiled GCC on and 4.X.Y is the GCC version you compiled)
Edit the just copied file ..../include-fixed/sys/cdefs.h to apply the following patch:
## -216,7 +215,7 ##
#if __STDC_VERSION__ >= 199901L && (!defined(__GNUC__) || defined(__clang__))
# define __header_inline inline
-#elif defined(__GNUC__) && defined(__GNUC_STDC_INLINE__)
+#elif defined(__GNUC__) && defined(__GNUC_STDC_INLINE__) && !defined (__cplusplus)
# define __header_inline extern __inline __attribute__((__gnu_inline__))
#elif defined(__GNUC__)
# define __header_inline extern __inline
This causes, when compiling c++ code, the expansion
__header_inline --> extern __inline
instead of
__header_inline --> extern __inline __attribute__((__gnu_inline__))
which would apparently cause GCC not to really inline isalnum and hence leave a link-time dependency on the symbol, i.e. it would try to find it in some library, leading to the link error.
Maybe you only installed the 32 bit part of gcc? Try -m32.
I tried to reinstall Xcode command line tools, since yesterday using
xcode-select --install
Unfortunately it doesn't work anymore, too
But then I was able to get it from
https://developer.apple.com/downloads/index.action
Unfortunately, reinstalling the command line tools didn't help either :(
I guess I will no go with
clang++ -std=c++11 -stdlib=libc++
until there is a official solution.