【问题标题】:Multiplatform C++ Project: Inclusion of platform specific sources多平台 C++ 项目:包含特定于平台的源
【发布时间】:2010-11-09 11:57:10
【问题描述】:

对于我的一些课程,每个操作系统都有不同的实现。
我的源码结构是这样的:

  • include/AExample.h
  • include/windows/WindowsExample.h
  • include/linux/LinuxExample.h
  • src/AExample.cpp
  • src/windows/WindowsExample.cpp
  • src/linux/LinuxExample.cpp

A* 类是特定实现的接口

我目前的构建系统是 cmake - 但目前它只能构建 linux 版本。

在 windows 构建中我只需要包含 windows/* 文件,在 linux 上只需要包含 linux/* 文件

我需要

  • 仅包含与我当前构建相关的文件
  • 当我需要 AExample 实例时选择正确的实现

您可以推荐哪些技术来以专业的方式实现这一点?

【问题讨论】:

    标签: c++ build cmake multiplatform


    【解决方案1】:

    这在 CMake 中相当容易。

    只需让您的 CMakeLists.txt 文件检查平台,并根据需要添加适当的文件或包含适当的子目录。

    基本语法是:

    IF(WIN32)
        # Do windows specific includes
    ELSEIF(UNIX)
        # Do linux specific includes
    ENDIF(WIN32)
    

    【讨论】:

      【解决方案2】:

      如果标头具有相同的名称但它们位于不同的层次结构中,您可以为您的编译器正确设置 -I(包含路径)标志。这比单独处理所有依赖于平台的包含要容易得多。

      如果标头位于同一目录中和/或您想要自定义内容,您通常会在您的 C/C++ 代码中执行此操作:

      #ifdef _WIN32
        .. include Win headers ..
      #endif
      
      #ifdef LINUX
        .. include Linux headers ...
      #endif
      

      除非您确定以后不需要切换构建系统,否则我不会推荐 cmake 特定的解决方案。

      【讨论】:

      • 不过,这不处理在构建中包含不同的源文件。使用 CMake 通常会导致适当地设置它,但您也可以包含特定于平台的源文件。这是首先使用 cmake 的(许多好的)原因之一。
      • 这是一种对小型项目很简单且效果很好的技术,但是当项目变得更大时就会出现问题。 Large Scale C++ Software Design 建议不要在整个源代码中进行平台检查。我认为使用构建系统来管理特定于平台的代码是最好的,但如果你想在源代码本身中执行它,建议使用更多的highly structured organization
      【解决方案3】:

      虽然我认为使用构建系统来处理跨平台文件是最好的,但可以简单地编写你的源代码来通过预处理器来处理它。然而,这种非常常见、快速和肮脏的方法,即在代码中散布平台检查是有问题的,应该避免。

      相反,您应该使用更高度结构化的方法来组织特定于平台的代码,以避免随着项目变得越来越大而出现问题。

      平台特定代码应在文件级别明确标识:例如,使用包含每个平台目录的目录结构,并将所有平台特定源文件放在适当的目录中。源文件不应包含用于多个平台的代码或任何预处理器平台检查(但有一个例外)。此外,平台特定的源通常不应直接构建或#included。相反,平台特定代码只能通过非平台特定源文件间接使用,这些源文件只包含平台检查和平台特定文件的#includes。

      示例来源组织:

      src/
        main.cpp
        foo.h
        foo.cpp
        windows/
          foo.cpp.inc
        posix/
          foo.cpp.inc
      

      示例源内容:

      // main.cpp
      #include "foo.h"
      
      int main() {
        foo();
      }
      
      // foo.h
      void foo();
      
      // foo.cpp
      #if defined(_WIN32)
      #  include "windows/foo.cpp.inc"
      #elif __has_include(<unistd.h>)
      #  include<unistd.h>
      #  if defined(_POSIX_VERSION)
      #    include "posix/foo.cpp.inc"
      #  endif
      #else
      #  error Unknown platform
      #endif
      
      // windows/foo.cpp.inc
      #include "foo.h"
      
      #include <iostream>
      #include <Windows.h>
      
      void foo() {
        std::cout << "Windows\n";
      }
      
      // posix/foo.cpp.inc
      #include "foo.h"
      
      #include <iostream>
      #include <unistd.h>
      
      void foo() {
        std::cout << "POSIX\n";
      }
      

      Windows 构建和输出:

      cl.exe /EHsc /W4 /WX src\main.cpp src\foo.cpp
      main

      窗户

      Linux 构建和输出:

      g++ -Wall -Wextra -Werror -Isrc src/main.cpp src/foo.cpp
      ./a.out

      POSIX

      当不同平台的代码可以合理地共享相同的文件组织时,上面示例中显示的方法效果很好。如果不同平台的代码差异很大,以至于您希望每个平台都有不同的文件结构,那么使用这种技术会更加困难,而转向使用构建系统来管理不同平台的代码会变得更加明显。

      也可以将这种技术与构建系统混合使用;跨平台共享文件结构的代码可以使用它,而不同平台特有的模块可以由构建系统处理。

      【讨论】:

        猜你喜欢
        • 2011-06-11
        • 2017-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多