Configure.sh

From Crypto++ Wiki
Jump to navigation Jump to search

configure.sh is a script to reconfigure the Crypto++ library for the specific compiler and platform you are targeting. The script can be used to fix misdetected features based on compiler versions and feature macros. Running configure.sh will correct the problems by performing compile tests and rewriting config_asm.h and config_cxx.h. Also see Issue 950, Can't compile on Android due to wrong evaluation of CRC support.

You should use the same compiler and flags for both the makefile and configure script by setting CXX and CXXFLAGS. You should also remove elevated diagnostics, like -Wall and -Wextra when running configure.sh. Examples of running the configure.sh script are shown below.

The script is relatively fast on a modern desktop, but takes about 20 seconds to run on a Raspberry Pi 3B and about 2 minutes to run on a Raspberry Pi 1B. The time is due to running the compiler and linker over source files about 40 times or so.

The makefile does not run configure.sh by default. It should be safe to run the script at anytime, however. If the script misdetects a feature then it is a bug in the script. Please report the bug.

configure.sh is located in the TestScripts/ folder. Copy it to the Crypto++ root directory before running it. The script was placed in the folder to avoid user confusion.

The configure.sh script was added to the library at Crypto++ 8.3. Also see Commit 36e0721f141b. It went through several revisions before becoming stable.

The meanings of the macros shown in the tests below are discussed in config.h. Most (all?) of the macros should be self-explanatory, though.

Native

There's nothing special about running configure.sh on a native platform, like your desktop computer. In the defines below, the various *_AVAILABLE defines mean the compiler and platform supports the feature, so it is OK to compile the source file. The code paths will be taken at runtime if the CPU supports the feature.

$ CXX=g++ ./configure.sh 
Configuring for x86_64
...

$ cat config_asm.h
#ifndef CRYPTOPP_CONFIG_ASM_H
#define CRYPTOPP_CONFIG_ASM_H

#define CRYPTOPP_X86_ASM_AVAILABLE 1
#define CRYPTOPP_X64_ASM_AVAILABLE 1
#define CRYPTOPP_SSE2_ASM_AVAILABLE 1
#define CRYPTOPP_SSE2_INTRIN_AVAILABLE 1
#define CRYPTOPP_SSE3_AVAILABLE 1
#define CRYPTOPP_SSSE3_ASM_AVAILABLE 1
#define CRYPTOPP_SSSE3_AVAILABLE 1
#define CRYPTOPP_SSE41_AVAILABLE 1
#define CRYPTOPP_SSE42_AVAILABLE 1
#define CRYPTOPP_CLMUL_AVAILABLE 1
#define CRYPTOPP_AESNI_AVAILABLE 1
#define CRYPTOPP_RDRAND_AVAILABLE 1
#define CRYPTOPP_RDSEED_AVAILABLE 1
#define CRYPTOPP_SHANI_AVAILABLE 1
#define CRYPTOPP_AVX_AVAILABLE 1
#define CRYPTOPP_AVX2_AVAILABLE 1
#define CRYPTOPP_PADLOCK_RNG_AVAILABLE 1
#define CRYPTOPP_PADLOCK_AES_AVAILABLE 1
#define CRYPTOPP_PADLOCK_SHA_AVAILABLE 1

#endif

Android

configure.sh will fix problems with feature detection on Android when targeting armv8. You should run configure.sh after running setenv-android.sh. Also see Android (Command Line) for more information on cross-compiling for Android.

In the output below notice the Android compiler supports CRC32, AES, PMULL and SHA. The default config_asm.h usually misdetects the features. (The features are not present in older NDK toolchains, but are available in newer NDK toolchains).

$ export ANDROID_API=28
$ export ANDROID_CPU=aarch64
$ source ./setenv-android.sh
...

$ CXXFLAGS="$ANDROID_CXXFLAGS --sysroot=$ANDROID_SYSROOT" ./configure.sh
Configuring for Aarch64
...

$ cat config_asm.h
#ifndef CRYPTOPP_CONFIG_ASM_H
#define CRYPTOPP_CONFIG_ASM_H

#define CRYPTOPP_ARM_NEON_HEADER 1
#define CRYPTOPP_ARM_ACLE_HEADER 1
#define CRYPTOPP_ARM_NEON_AVAILABLE 1
#define CRYPTOPP_ARM_ASIMD_AVAILABLE 1
#define CRYPTOPP_ARM_CRC32_AVAILABLE 1
#define CRYPTOPP_ARM_AES_AVAILABLE 1
#define CRYPTOPP_ARM_PMULL_AVAILABLE 1
#define CRYPTOPP_ARM_SHA_AVAILABLE 1
#define CRYPTOPP_ARM_SHA1_AVAILABLE 1
#define CRYPTOPP_ARM_SHA2_AVAILABLE 1
#define CRYPTOPP_DISABLE_ARM_SHA3 1
#define CRYPTOPP_DISABLE_ARM_SHA512 1
#define CRYPTOPP_DISABLE_ARM_SM3 1
#define CRYPTOPP_DISABLE_ARM_SM4 1

#endif

iOS

configure.sh will fix problems with feature detection on iOS when targeting arm64. You should run configure.sh after running setenv-ios.sh. Also see iOS (Command Line) for more information on cross-compiling for iOS.

In the output below notice the iOS compiler does not support CRC32 or PMULL. The default config_asm.h can usually detect the situation.

$ export IOS_SDK=iPhoneOS
$ export IOS_CPU=arm64
$ source ./setenv-ios.sh
...

$ CXXFLAGS="$IOS_CXXFLAGS --sysroot=$IOS_SYSROOT" ./configure.sh 
Configuring for Aarch64
...

$ cat config_asm.h
#ifndef CRYPTOPP_CONFIG_ASM_H
#define CRYPTOPP_CONFIG_ASM_H

#define CRYPTOPP_ARM_NEON_HEADER 1
#define CRYPTOPP_ARM_NEON_AVAILABLE 1
#define CRYPTOPP_ARM_ASIMD_AVAILABLE 1
#define CRYPTOPP_DISABLE_ARM_CRC32 1
#define CRYPTOPP_ARM_AES_AVAILABLE 1
#define CRYPTOPP_DISABLE_ARM_PMULL 1
#define CRYPTOPP_ARM_SHA_AVAILABLE 1
#define CRYPTOPP_ARM_SHA1_AVAILABLE 1
#define CRYPTOPP_ARM_SHA2_AVAILABLE 1
#define CRYPTOPP_DISABLE_ARM_SHA3 1
#define CRYPTOPP_DISABLE_ARM_SHA512 1
#define CRYPTOPP_DISABLE_ARM_SM3 1
#define CRYPTOPP_DISABLE_ARM_SM4 1

#endif

C++

configure.sh will fix problems with C++ feature detection. C++ features are less of a problem nowadays, but a misdetection could occur. The last time we saw regular problems with C++ feature detection was around C++11 due to Apple's C++03 runtime library pretending to be a C++11 library. However, "magic statics" (N2660) still seem to be a problem; see LLVM Issue 47012.

A typical rewrite of config_cxx.h from Ubuntu 18.04 with GCC 7.5 is shown below. Notice the compiler is C++14.

$ cat config_cxx.h
#ifndef CRYPTOPP_CONFIG_CXX_H
#define CRYPTOPP_CONFIG_CXX_H

// ***************** C++98 and C++03 ********************

// Ancient Crypto++ define, dating back to C++98.
#define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE 1
#define CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION 1

// ***************** C++11 and above ********************

#define CRYPTOPP_CXX11 1

#if defined(CRYPTOPP_CXX11)

#define CRYPTOPP_CXX11_ATOMIC 1
#define CRYPTOPP_CXX11_AUTO 1
#define CRYPTOPP_CXX11_SYNCHRONIZATION 1
#define CRYPTOPP_CXX11_STATIC_INIT 1
#define CRYPTOPP_CXX11_DYNAMIC_INIT 1
#define CRYPTOPP_CXX11_DELETED_FUNCTIONS 1
#define CRYPTOPP_CXX11_ALIGNAS 1
#define CRYPTOPP_CXX11_ALIGNOF 1
#define CRYPTOPP_CXX11_INITIALIZER_LIST 1
#define CRYPTOPP_CXX11_LAMBDA 1
#define CRYPTOPP_CXX11_NOEXCEPT 1
#define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1
#define CRYPTOPP_CXX11_CONSTEXPR 1
#define CRYPTOPP_CXX11_STRONG_ENUM 1
#define CRYPTOPP_CXX11_NULLPTR 1
#define CRYPTOPP_CXX11_ASSERT 1

#endif  // CRYPTOPP_CXX11

// ***************** C++14 and above ********************

#define CRYPTOPP_CXX14 1

#if defined(CRYPTOPP_CXX14)

// No dead bodies here. Move on...

#endif  // CRYPTOPP_CXX14

// ***************** C++17 and above ********************

// test_cxx17.cxx returned non-zero result
// #define CRYPTOPP_CXX17 1

#if defined(CRYPTOPP_CXX17)

// #define CRYPTOPP_CXX17_ASSERT 1
#define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS

#endif  // CRYPTOPP_CXX17

// ***************** C++ fixups ********************

#if defined(CRYPTOPP_CXX11_NOEXCEPT)
#  define CRYPTOPP_THROW noexcept(false)
#  define CRYPTOPP_NO_THROW noexcept(true)
#else
#  define CRYPTOPP_THROW
#  define CRYPTOPP_NO_THROW
#endif // CRYPTOPP_CXX11_NOEXCEPT

// C++11 nullptr_t type safety and analysis
#if defined(CRYPTOPP_CXX11_NULLPTR) && !defined(NULLPTR)
#  define NULLPTR nullptr
#elif !defined(NULLPTR)
#  define NULLPTR NULL
#endif // CRYPTOPP_CXX11_NULLPTR

#endif

If a C++ feature is not available then the define will be commented out. Below is from OS X 10.12 using Apple Clang 9.0. Notice the compiler is C++11 but does not support "magic statics". The test uses __cpp_threadsafe_static_init, which the compiler does not define to the expected value of 200806L.

#define CRYPTOPP_CXX11_ATOMIC 1
#define CRYPTOPP_CXX11_AUTO 1
#define CRYPTOPP_CXX11_SYNCHRONIZATION 1
// #define CRYPTOPP_CXX11_STATIC_INIT 1
#define CRYPTOPP_CXX11_DELETED_FUNCTIONS 1
#define CRYPTOPP_CXX11_ALIGNAS 1
#define CRYPTOPP_CXX11_ALIGNOF 1
#define CRYPTOPP_CXX11_INITIALIZER_LIST 1
#define CRYPTOPP_CXX11_LAMBDA 1
#define CRYPTOPP_CXX11_NOEXCEPT 1
#define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1
#define CRYPTOPP_CXX11_CONSTEXPR 1
#define CRYPTOPP_CXX11_STRONG_ENUM 1
#define CRYPTOPP_CXX11_NULLPTR 1
#define CRYPTOPP_CXX11_ASSERT 1

Tests

Most feature tests have a specialized test located in TestPrograms. A feature test without a specialized test just uses test_cxx.cxx. The test file test_cxx.cxx only includes the C++ header <string>.

The feature test passes if the source file compiles and links cleanly. If there is any noise then the test fails. This is called a "dark and silent cockpit" in aviation. In aviation, lights off and no buzzers is good; while lights flashing and buzzers sounding is bad.

For example, here is the compile test for C++11 "magic statics". The wc command counts the words in the output. If there is a compiler diagnostic or error, then there will be non-0 word count and the test fails.

CXX_RESULT=$(${CXX} ${CXXFLAGS} TestPrograms/test_cxx11_dyninit.cxx -o ${TOUT} 2>&1 | wc -w)
if [[ "${CXX_RESULT}" -eq 0 ]]; then
  echo '#define CRYPTOPP_CXX11_STATIC_INIT 1'
else
  echo '// #define CRYPTOPP_CXX11_STATIC_INIT 1'
fi

The test was needed like this because some compilers don't return an error when it should. Instead, it outputs an informational message like "Illegal option -xarch=sha" with a return value of 0.

You can run the test manually to see what is happening. Below is from OS X 10.12 and Apple Clang 9.0.

$ export CXX=clang++
$ export CXXFLAGS="-DNDEBUG -g2 -O3 -std=c++11"
$ ${CXX} ${CXXFLAGS} TestPrograms/test_cxx11_dyninit.cxx
test_cxx11_dyninit.cxx:8:11: error: 'x' declared as an array with a negative size
    int x[-1];
          ^~
1 error generated.

The int x[-1]; code path means the feature was not present.

$ cat TestPrograms/test_cxx11_dyninit.cxx
int main(int argc, char* argv[])
{
#if __cpp_threadsafe_static_init >= 200806L
    int x[1];
#else
    int x[-1];
#endif
    return 0;
}