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.
Related
According to cppreference, the gcc libstdc++ supports the parallelism TS. In layperson terms and for what's relevant for me that means #include <execution> works in g++ 9 and doesn't work in g++ 8 or before. In my source code I can handle this with
#if ( defined( __GNUC__ ) && __GNUC__ > 8 )
# define can_use_std_execution
# include <execution>
#endif
For my clang++ builds, the availability of <execution> depends on the --gcc-toolchain that I use. So instead of checking the __clang_major__, I'd like to check the gcc libstdc++ version in the preprocessor.
As far as I see in this compiler-explorer example, __GNUC__ is defined in clang but the compilation command is
-g -o /tmp/compiler-explorer-compiler120120-1672-4ffux6.smufm/output.s -mllvm --x86-asm-syntax=intel -S --gcc-toolchain=/opt/compiler-explorer/gcc-8.3.0 -fcolor-diagnostics -fno-crash-diagnostics /tmp/compiler-explorer-compiler120120-1672-4ffux6.smufm/example.cpp
i.e. the gcc toolchain is from gcc 8.3.0, but the value of __GNUC__ is 4.
What's a good way to query the gcc toolchain version in the preprocessor with clang? Ideally a way that checks the libstdc++ version in a way that's compatible for g++ and clang++ such that I don't have write a spaghetti if that checks the compiler first.
Grepping for ^#.*define.*9 in the compiler headers of gcc 9 it seems that
#include <bits/c++config.h>
#if _GLIBCXX_RELEASE > 8
# include <execution>
#endif
can do the job. From this conformance view this variable was introduced with the toolchain of gcc 7.
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.
In CLion using Cygwin, when I try to open a certain c++ project, I get the following error when parsing the project's CMake file:
Error:Configuration emdw [Debug]
Compiler exited with error code 1: g++ -xc++ -Demdw_EXPORTS -I/cygdrive/c/Users/Dirk/.CLion2016.2/system/cmake/generated/emdw-e21eebc3/e21eebc3/Debug/src -I/cygdrive/f/devel/emdw/src -I/cygdrive/f/devel -I/cygdrive/f/devel/patrecII/src -std=c++11 -O3 -g -Wall -v -dD -E
g++.exe: error: #/cygdrive/f/users/heetbeet/AppData/Local/Temp/compiler-arguments.txt: No such file or directory
g++.exe: error: /cygdrive/f/users/heetbeet/AppData/Local/Temp/compiler-file: No such file or directory
g++.exe: fatal error: no input files
compilation terminated.
I take it CLion generate these type of compiler-arguments.txt / compiler-file files, since no such instructions are found in the actual CMake structure. Note that I can successfully run cmake.exe on this project from Cygwin's bash without any errors.
What magic is CLion trying to achieve with the compiler-arguments.txt file (if it is CLion), and how do I begin to debug this problem?
I can confirm that upon clicking the Reload CMake Project button in CLion,
two files named compiler-arguments.txt and compiler-file are indeed created in F:\users\heetbeet\AppData\Local\Temp (that is /cygdrive/f/users/heetbeet/AppData/Local/Temp/ in Cygwin).
The content of compiler-arguments.txt is:
-xc++ -Demdw_EXPORTS -I/cygdrive/c/Users/Dirk/.CLion2016.2/system/cmake/generated/emdw-e21eebc3/e21eebc3/Debug/src -I/cygdrive/f/devel/emdw/src -I/cygdrive/f/devel -I/cygdrive/f/devel/patrecII/src -std=c++11 -O3 -g -Wall -v -dD -E -D___CIDR_IGNORE_DEFINITIONS_START
The compiler-file contains a bunch of #if's, #ifdef's, with the first 20 lines as:
#define ___CIDR_IGNORE_DEFINITIONS_END
#if !(defined (__has_extension)) && defined(__has_feature)
#define __has_extension __has_feature
#endif
#if !defined(__has_attribute)
#define __has_attribute(x) 0
#endif
#ifdef __has_feature
#if __has_feature(cxx_constexpr)
____CIDR_test_query_feature->cxx_constexpr=1
#else
____CIDR_test_query_feature->cxx_constexpr=0
#endif
#if __has_feature(cxx_trailing_return)
____CIDR_test_query_feature->cxx_trailing_return=1
#else
____CIDR_test_query_feature->cxx_trailing_return=0
#endif
#if __has_feature(c_generic_selections)
____CIDR_test_query_feature->c_generic_selections=1
<...>
We need to create AST of your source files somehow. To make it right we need the compiler-specific macros and features FOR EACH c/cpp-file in your project, because you can change the compiler option for each one. So that is the price you are paying for right highlighting and macro evaluation in cross-platform project.
About the issue: you are using cygwin and I have feeling that the problem can be resolved by chmod 777 calls.
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'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.