Someday You'll Write Code That Runs Everywhere
\nImagine: you create a cool project in C++, everything works perfectly on Windows. Your friend asks you to build a version for Linux. You sigh, dive into the Makefile, change paths, compilers, stumble upon #ifdef _WIN32, and three hours later you get a binary that still crashes with a segmentation fault. Sound familiar?
Cross-platform development in C++ is not magic, but a set of disciplines and tools. In this article, we'll break down how to write code that works on Windows, Linux, and macOS without tears, with real code examples and ready-made solutions. Let's go!
\n\nWhy C++ is Ideal for Cross-Platform (And Why It's a Pain)
\nC++'s strengths — compilability, performance, and memory control — make it the king of system programming. But you have to pay for it: each OS has its own APIs, compilers (MSVC, GCC, Clang), and file system peculiarities.
\nThe main pitfalls:
\n- \n
- Different header files —
windows.hvsunistd.h\n - Different macros —
_WIN32,__linux__,__APPLE__\n - Different compilers — MSVC doesn't like GCC extensions \n
- Different libraries — dynamic loading (DLL vs .so) \n
But don't worry — all these problems are solvable. The main thing is to choose the right approach from the start.
\n\nTool #1: CMake — Your Universal Builder
\nIf you're writing a cross-platform application in C++, your best friend is CMake. It's not a build system like Make, but a build file generator: it creates Makefiles for Linux/macOS and .sln for Visual Studio on Windows.
\nHere's a minimal CMakeLists.txt that works everywhere:
cmake_minimum_required(VERSION 3.16)\nproject(CrossPlatformApp VERSION 1.0 LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n# Add executable\nadd_executable(myapp main.cpp utils.cpp)\n\n# Cross-platform handling\nif(WIN32)\n target_compile_definitions(myapp PRIVATE PLATFORM_WINDOWS)\n target_link_libraries(myapp PRIVATE ws2_32) # sockets on Windows\nelseif(APPLE)\n target_compile_definitions(myapp PRIVATE PLATFORM_MACOS)\n target_link_libraries(myapp PRIVATE "-framework CoreFoundation")\nelse()\n target_compile_definitions(myapp PRIVATE PLATFORM_LINUX)\nendif()\nAs you can see, target_compile_definitions allows you to set macros for each platform. In code, you use them like this:
#ifdef PLATFORM_WINDOWS\n #include <windows.h>\n void sleep_ms(int ms) { Sleep(ms); }\n#else\n #include <unistd.h>\n void sleep_ms(int ms) { usleep(ms * 1000); }\n#endif\nCMake is the de facto standard. If your project doesn't use it, it's time to change your approach.
\n\nBoost and Qt: Ready-Made Solutions for Complex Tasks
\nWriting everything from scratch is for heroes and masochists. For cross-platform development in C++, there are mature libraries that hide OS differences.
\nBoost — Swiss Army Knife
\nBoost.Asio — for network programming (works on both Windows and Linux). Boost.Filesystem — for file operations (replaces std::filesystem if you have an old compiler). Example of cross-platform directory reading:
#include <boost/filesystem.hpp>\nnamespace fs = boost::filesystem;\n\nvoid list_files(const std::string& path) {\n for (const auto& entry : fs::directory_iterator(path)) {\n std::cout << entry.path().string() << std::endl;\n }\n}\nThis code will compile on any OS without a single #ifdef.
Qt — Full-Featured Framework
\nIf you need a GUI, networking, databases, or multithreading — Qt is your choice. It provides a unified API for all platforms. When