Coding Architect

You never know what you can do till you try.

Lab notebook: Porting 550K LoC of C/C++ from Windows to Linux

As a part of Native Cloud transformation at my work I’ve ported a financial library from Windows to Linux. The library consists of 250K LoC of C and 300K LoC of C++. Some of the code is 20 years old. During the last 10 years it has been developed with MSVC++ exclusively for Windows. I wanted to port the code to GCC/Linux and keep the MSVC++/Windows build error-free in the same time.

About 70% of the porting efforts were spent on adaption of the legacy C++ code to C++14 standard. The porting took roughly 2 months.

Here is the summary of my learning from the project:

  • Keep the log of faced errors and their solutions like this one. It’s a huge time saver and helps answering code review questions as well.

  • Patience and determination are the keys. Don’t be discouraged by megabytes of compilation error log at the start. Progress will be very slow in the beginning, but then things start to speedup almost exponentially: in the first 3 weeks I made only 3% of progress, then it took only 2 days to go from 60% to 100%. The “exponential law” applies to both compilation and linking errors.

  • Implement CI for the existing platform and for the new platform/compiler from very beginning. Keep your changes small, so it will be easy to revert the code to the last “good” state in case something goes wrong.

  • Use CMake, it’s quite convenient and it allows to track progress as well.

  • Porting of Unicode-related code can be tricky.

  • Don’t cut corners with -fpermissive.

What I would do differently:

  • Establish a build with clang to get more understandable build error messages for C++ code.

Docs and References

C++ Resources

https://en.cppreference.com

http://www.cplusplus.com/reference/

Draft of C++ standard

Online C++ compiler

C++ features support by compilers

C++ compiler support

MSVC++: Support For C++11/14/17 Features (Modern C++)

GNU Compiler and Library References

Using the GNU Compiler Collection (GCC)

The GNU C++ Library

GNU: Options Controlling C++ Dialect

Preprocessor and predefined compiler-specific macros

Guide to predefined macros in C++ compilers (gcc, clang, msvc etc.)

MSVC/MSVC++ Predefined Macros

GNU: Common Predefined Macros

C/C++ tip: How to list compiler predefined macros

g++ -std=c++14 -dM -E -x c++ /dev/null | sort

Save temp files:

g++ -save-temps -c file.cc

See: https://stackoverflow.com/questions/35537350/gcc-optional-preprocessor-output-and-compilation-in-one-pass

GNU: Preprocessor Output

Windows-specific types

Windows Data Types

UNIX Compatibility

Faced issues

// replace
typedef std::basic_string<char, string_char_traits<char>> mystring;
// with
typedef std::basic_string<char> mystring;
  • Missing min and max can be declared as:
#ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
aa::bb::cc;

Surprisingly the line, which doesn’t make any sense, is processed by VS2013 compiler. Delete it.

X(MyType& arg = MyType()) {
    ...
}
// to
X(const MyType& arg = MyType()) {
    ...
}
template class A<T1>;
template class A<T2>;

Possible solutions: use #ifdef, use std::conditional https://stackoverflow.com/questions/13925730/conditional-explicit-template-instantiation, or use C++17 if constexpr() (requires GCC7, VS2017 15.3) https://tech.io/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/constexpr-if

// from
template <T>
ReturnType<T> ns::method<T>(InputArg arg) {
    //...
}

// to
template <T>
ReturnType<T> ns::method(InputArg arg) {
    //...
}
#include <linux/limits.h>
#define MAX_PATH PATH_MAX
#define _MAX_PATH PATH_MAX

Unicode portability issues

If the code uses Windows-specific tchar.h, then look into http://www.rensselaer.org/dept/cis/software/g77-mingw32/include/tchar.h also read https://www.tldp.org/HOWTO/Unicode-HOWTO-6.html, http://pubs.opengroup.org/onlinepubs/7908799/xsh/wchar.h.html.

  • Missing TCHAR:
 typedef wchar_t TCHAR;
#define _T(x) L##x

Linker errors

Linking phase certifies the entire porting process.