How to make sure win-builder builds my package with c++11? - c++

I'm trying to make my package (code available here) pass win-builder tests so I can upload to cran. The package relies heavily in Rcpp and I use some things that require C++11 standard. But the win-builder test results keep showing a number of warnings like the following:
warning: delegating constructors only available with -std=c++11 or -std=gnu++11
warning: extended initializer lists only available with -std=c++11 or -std=gnu++11
I tried to make a minimal test with the Rcpp.package.skeleton() example package, adding a few extended initializer list uses, and a Makevars file containig just the one line:
CXX_STD = CXX11
but the minimal test works fine. You can see in the win-builder test results for the minimal test that it's compiling with -std=gnu++11, whereas my package is being compiled without that option:
Minimal test:
*** arch - i386
d:/Compiler/gcc-4.9.3/mingw_32/bin/g++ -std=gnu++11 -I"D:/RCompile/recent/R/include" -DNDEBUG -I"d:/RCompile/CRANpkg/lib/3.5/Rcpp/include" -I"d:/Compiler/gcc-4.9.3/local330/include" -O2 -Wall -mtune=core2 -c RcppExports.cpp -o RcppExports.o
My package:
*** arch - i386
d:/Compiler/gcc-4.9.3/mingw_32/bin/g++ -I"D:/RCompile/recent/R/include" -DNDEBUG -I"d:/RCompile/CRANpkg/lib/3.5/Rcpp/include" -I"d:/Compiler/gcc-4.9.3/local330/include" -pedantic -O2 -Wall -mtune=core2 -c Individual.cpp -o Individual.o
Why are they compiled with different options? I'm using the exact same Makevars file. Just in case it's relevant, I have these lines on my DESCRIPTION:
Imports:
Rcpp (>= 0.12.14),
Matrix,
grid,
animation
LinkingTo: Rcpp
Suggests:
knitr,
rmarkdown
Depends:
R (>= 3.1.0)
License: GPL-2
LazyData: true
RoxygenNote: 6.0.1
URL: https://github.com/Lobz/facilitation
VignetteBuilder: knitr
EDIT: I copied the above into the minimal test package's DESCRIPTION file to make them more similar, and the minimal test file still compiles properly with -std=gnu++11.
Note: I upload the packages to win-builder via devtools::build_win().

Try adding in DESCRIPTION
SystemRequirements: C++11
This avoids the need of having to specify a custom Makevars for different platforms (e.g. Makevars for Unix + Solaris + macOS, Makevars.win for windows).
However, as #DirkEddelbuettel said, C++11 support on Windows exist; but, the completeness of the C++11 implementation with gcc-4.9.3 is problematic on the library side

Related

Controlling scons environment checking options

I'm trying to build mongodb (open source version 4.2) which uses python and scons for building. The problem relates to scons rather than mongodb.
My build fails very early with Couldn't find OpenSSL crypto.h header and library. Verbose details are:
file /.../SConstruct,line 3042:
Configure(confdir = build/scons/opt/sconf_temp)
scons: Configure: Checking for SSLeay_version(0) in C library crypto...
build/scons/opt/sconf_temp/conftest_d6743137aeb7fb2674cc9632f9989034_0.c <-
|
|
|#include "openssl/crypto.h"
|
|int
|main() {
| SSLeay_version(0);
|return 0;
|}
|
gcc -o build/scons/opt/sconf_temp/conftest_d6743137aeb7fb2674cc9632f9989034_0.o -c -std=c11 -ffp-contract=off -fno-omit-frame-pointer -fno-strict-aliasing -ggdb -pthread -Wall -Wsign-compare -Wno-unknown-pragmas -Winvalid-pch -Werror -O2 -Wno-unused-local-typedefs -Wno-unused-function -Wno-deprecated-declarations -Wno-unused-const-variable -Wno-unused-but-set-variable -Wno-missing-braces -Wno-exceptions -fstack-protector-strong -fno-builtin-memcmp -fPIE -DNDEBUG -D_XOPEN_SOURCE=700 -D_GNU_SOURCE build/scons/opt/sconf_temp/conftest_d6743137aeb7fb2674cc9632f9989034_0.c
cc1: error: command-line option '-Wno-exceptions' is valid for C++/ObjC++ but not for C [-Werror]
cc1: all warnings being treated as errors
scons: Configure: no
I'm using Arch Linux which has multiple OpenSSL packages, and the default 3.0 is not compatible with mongodb source. I also have OpenSSL 1.1 and 1.0 installed, and can switch with e.g. gcc -I/usr/include/openssl-1.1.
Unfortunately I have not found a way to instruct SConstruct to use this flag in the command lines it generates to check the environment. I have tried CFLAGS, CCFLAGS, CPPPATH both as environment variables and scons command line parameters.
I also tried reverse enginering it, and tracked this to Conftest and TryBuild but it's not obvious how I can influance theses from the command line, so I'm trying my luck with you guys before going deeper in scons code.
If you look at the SConstruct and search for openssl, you'll find this blurb under the logic to detect on macOS
NOTE: Recent versions of macOS no longer ship headers for the system OpenSSL libraries.
NOTE: Either build without the --ssl flag, or describe how to find OpenSSL.
NOTE: Set the include path for the OpenSSL headers with the CPPPATH SCons variable.
NOTE: Set the library path for OpenSSL libraries with the LIBPATH SCons variable.
NOTE: If you are using HomeBrew, and have installed OpenSSL, this might look like:
\tscons CPPPATH=/usr/local/opt/openssl/include LIBPATH=/usr/local/opt/openssl/lib ...
NOTE: Consult the output of 'brew info openssl' for details on the correct paths."""
I'd bet if you did the same but pointed at the proper locations on your system for the openssl libs and header files, you'd be able to build.
(see: https://github.com/mongodb/mongo/blob/r4.2.0/SConstruct#L3015 )

How to find and provide C++ library headers for clang?

I've built LLVM and Clang from sources using following instruction in order to try some of the latest C++ features.
When I try to compile basic C++ program using this clang I get errors about missing basic headers:
% /usr/local/bin/clang++ -std=c++20 main.cpp
In file included from main.cpp:1:
main.cpp:3:10: fatal error: 'array' file not found
#include <array>
I similarly have brew installed clang, which works perfectly.
The instruction mentions providing C++ library headers to clang, but I don't understand:
How to locate those?
How to make sure, that they are also up to date to support latest C++ features?
I have MacOS Monterey 12.4
You should specify a path to the sdk for your target platform.
You can retreive this by relying on xcrun:
/usr/local/bin/clang++ -isysroot $(xcrun --show-sdk-path) -std=c++20 main.cpp
In case you want to target other platforms (in the example bellow, for iphone) you have to specify both the target triple and the path to the appropiate sdk:
/usr/local/bin/clang++ -target arm64-apple-ios -isysroot $(xcrun --sdk iphoneos --show-sdk-path) -std=c++20 main.cpp
There is also an alternative to the -isysroot option. You could set up the SDKROOT environment variable to point to the target sdk path:
export SDKPATH=$(xcrun --show-sdk-path)
/usr/local/bin/clang++ -std=c++20 main.cpp

--with-sysroot is not honored during a compile on OS X?

I have a C++ project. I am testing a cross-compile with Autotools on OS X for iOS. I configure with:
$ echo $IOS_SYSROOT
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.2.sdk
$ CXXFLAGS="-DNDEBUG -g2 -O3 -arch arm64" ./configure --with-sysroot="$IOS_SYSROOT" --build=`config.guess` --host=aarch64-ios
When make'ing it results in (line breaks added for clarity):
libtool: compile: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++
-DHAVE_CONFIG_H -I. ... -DNDEBUG -g2 -O3 -arch arm64 -MT adhoc.lo -MD -MP -MF .deps/adhoc.Tpo -c adhoc.cpp -o adhoc.o
In file included from adhoc.cpp:2:
In file included from /usr/include/c++/4.2.1/iosfwd:44:
In file included from /usr/include/c++/4.2.1/bits/c++config.h:41:
In file included from /usr/include/c++/4.2.1/bits/os_defines.h:61:
In file included from /usr/include/unistd.h:71:
In file included from /usr/include/_types.h:27:
In file included from /usr/include/sys/_types.h:32:
/usr/include/sys/cdefs.h:658:2: error: Unsupported architecture
#error Unsupported architecture
...
Notice the wrong header files are being used. The build system's headers are used rather than the iPhone headers. I'm fairly certain --with-sysroot is not being honored. Searching for the keywords seems to indicate its a widespread problem with Autoconf (based on all the bug reports trying to use the feature).
Manually adding CXXFLAGS="-sysroot=$IOS_SYSROOT -arch arm64 ... seems to fix the issue. This seems to be the same problem (or nearly the same problem) detailed at Bug 79885: --with-build-sysroot= does not get honored throughout the build.
There does not seem to be a AC_SYSROOT (or similar) to copy --with-sysroot into AM_CXXFLAGS. Searching the Autoconf site for the keywords is not returning useful hits: "--with-sysroot" site:https://www.gnu.org/software/autoconf/manual.
How are we supposed to handle Autoconf's --with-sysroot option? What is the practice packagers are supposed to follow?
Here are the Autoconf prject files: cryptopp-autotools. There are two files of interest, and they are configure.ac and Makefile.am. I'm not sure what applies to this problem at the moment.
Here's the message where Autoconf tells users to use it:
$ ./configure --help | grep sysroot
--with-sysroot[=DIR] Search for dependent libraries within DIR (or the
compiler's sysroot if not specified).
I'd prefer to supress the message if Autoconf cannot wire-in --with-sysroot properly. Otherwise, users are going to be filling bug reports against us.

Automatically select a C++11-compatible g++ version in the Makefile

The problem:
2 version of g++ installed on a computer running Ubuntu 12.04. They are the versions 4.6 and 5.2.
I have to compile a C++11 program using a Makefile. If I use g++ as compiler it calls automatically the version 4.6, it does not support c++11 so the compilation fails. I've followed a tutorial online, so that now if I call g++ it calls automatically the version 5.2 and now it works.
I find this solution not so good, since it works only on my PC. Is there a way to recognize in the Makefile if the default g++ version support C++11 and, in case not, switch to a more recent version?
Thank you!
Is there a way to recognize in the Makefile if the default g++ version support C++11 and, in case not, switch to a more recent version?
You can certainly detect the version of the default compiler available in PATH in your makefile. However, where do you search for another version?
The standard approach is to let the user specify the C compiler through CC and C++ compiler through CXX make variables, e.g.: make CC=/path/to/my/gcc CXX=/path/to/my/g++.
You can always select which gcc to use while invoking make
make CXX=/gcc/path/of/your/choice
otherwise you can detect gcc version using
ifdef CXX
GCC_VERSION = $(shell $(CXX) -dumpversion)
else
GCC_VERSION = $(shell g++ -dumpversion)
endif
in Makefile and while using, you can test if your gcc is >=4.6
ifeq ($(shell expr $(GCC_VERSION) '>=' 4.6), 1)
UPDATE: newer gcc needs -dumpfullversion together (icx is the CC from Intel OneAPI)
$ icx -dumpversion
14.0.0
$ gcc -dumpversion
9
$ icx -dumpfullversion -dumpversion
14.0.0
$ gcc -dumpfullversion -dumpversion
9.3.1
One very simple way is to use conditional statements in your makefile, and go for versions which you know are compatible, and only use the default gcc as a fallback. Here's a basic example:
CXX=g++
ifeq (/usr/bin/g++-4.9,$(wildcard /usr/bin/g++-4.9*))
CXX=g++-4.9
# else if... (a list of known-to-be-ok versions)
endif
The other, more robust method, is to generate your makefile using a script that checks for capabilities using test compilations, kind of like what ./configure usually does. I really don't mean to recommend autotools, though.
The thing to do is build your Makefile to use as many implicit rules as possible. By default compilation uses various environment variables.
The variable $(CXX) is the C++ compiler command and defaults to g++ on Linux systems. So clanging CXX to a different compiler executable will change the compiler for all implicit compile commands.
When you write explicit rules use the same variable that the implicit rules use. So instead of this:
program: program.cpp
g++ -o program program.cpp
Do this:
program: program.cpp
$(CXX) -o program program.cpp
Other variables you should use are:
CPPFLAGS = -Iinclude
CXXFLAGS = -std=c++14 -g3 -O0
Those are for pre-processing flags CPPFLAGS and compiler flags CXXFLAGS and library linking flags LDLIBS.
Using the default environment variables allows the person compiling the project the freedom to control the compilation for their desired environment.
See the GNU make manual
This works for me:
cmake_minimum_required(VERSION 2.8.11)
project(test)
if (${CMAKE_CXX_COMPILER_VERSION} LESS 5.0)
message(FATAL_ERROR "You need a version of gcc > 5.0")
endif (${CMAKE_CXX_COMPILER_VERSION} LESS 5.0)
add_executable(test test.cpp)
You can check in your source code the gcc version and abort compilation if you don't like it. Here is how it works:
/* Test for GCC > 4.6 */
#if !(__GNUC__ > 3 && __GNUC_MINOR__ > 6)
#error gcc above version 4.6 required!
#endif

Rcpp Library Won't Build (Can't find Compiler) on Ubuntu

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.