【问题标题】:Official C++/11 Makefile Standard/Alternatives?官方 C++/11 Makefile 标准/替代方案?
【发布时间】:2013-05-20 15:45:37
【问题描述】:

我目前正在使用 Visual Studio 2012、Eclipse、CodeBlocks 和 MinGW 编写 C++ 11 代码。

问题:

我注意到 GCC 中的功能(延迟、= 与即时、:=、扩展/分配等)以及 Microsoft 的 nmake,这让我想知道官方的“makefile”标准是什么。

  1. 是否对 C++11 的 makefile 标准进行了更新?
  2. 我知道 GNU makefile 标准在哪里 (http://www.gnu.org/software/make/manual/make.html),但我在哪里可以找到“The”makefile 标准?
  3. 说实话,我更愿意用 C++ 编写 makefile,然后将它们作为脚本从 shell 中运行;有没有办法将 C++ 代码作为脚本运行?也许是Javascript?还使用了哪些其他脚本语言来执行此操作?

背景:

困难,(*咳嗽),是我试图确保代码在每个环境中编译,以及尝试交叉编译到其他目标,(Linux/Ubuntu 使用 OpenGL API,Windows 7 ,8,使用 DirectX,Android NDK)。

我的一个核心问题是,我使用的许多工具集并没有真正“开放”以支持跨平台的强大功能。

Visual Studio 2012: 没有 *nix 可运行编译器。 使用错误版本的 2012 年 11 月 C++ CTP 编译器来支持 C++11。

GCC 4.7.x/4.8x: 仅限于 MinGW32 和 MinGW64 的粗略版本。

CMake: 很难正确配置,但似乎会创建特定于 GNU、Microsoft 等的 makefile。有什么方法可以配置它以生成“标准”makefile?

AutoMake/AutoConf: 似乎只生成 GNU 兼容的 makefile

【问题讨论】:

  • makefile和c++是两个独立的东西
  • Make 以及大多数构建系统都是独立于语言的。虽然有一些“最佳实践”,但它们更多地取决于您正在使用的构建系统(CMake、gnu make 等),而不是您正在构建的语言。

标签: c++ c++11 makefile build-automation portability


【解决方案1】:

make 系统没有 C++ 标准。这纯粹是实现定义的东西。

对于跨平台工作(既是跨操作系统又是跨工具链),我发现最流行的选择是CMake。我不喜欢 CMake 的语法或各种复杂性,我不喜欢使用它——但它确实有效,而且似乎每个人都在使用它。您在一个项目中获得的 CMake 技能将转移到许多其他项目。

是的,您可以从 CMake 中获取“标准”makefile。这是生成器的功能:

cmake -G "Unix Makefiles" ...

将生成与 *nix make 兼容的 makefile。

【讨论】:

  • 谢谢!这回答了所有标准问题。 :) makefile 语法有什么替代方法吗?我的意思是,是否有能够操作文件夹、文件和执行命令的 javascript 脚本库?或者也许是在各种平台上将 C++ 作为脚本运行的一种方式?
  • C++ 不是脚本语言,因此无法直接将 C++ 作为脚本运行。但是,世界上有许多脚本语言,例如 Ruby、Perl 和 Python,也许其中一种会满足您的需求。顺便说一句,我提到的所有语言都是免费的、开源的,并且包含在标准 Linux 发行版中。它们在不同程度上易于使用且功能强大。
  • @WindAndFlame 如果你想要跨平台构建代码,以命令式编程语言实现,你可以查看使用 python 的scons。我发现它没有 CMake 那么痛苦,尽管它没有被广泛使用(事实上,出于这个原因,我从来没有真正使用过它)。
  • 我没有使用cmake 的经验,但我在所有常用平台上都使用过 GNU make。 Windows 有一个端口,它使用 autoconf,因此它可以在所有(或至少几乎所有)Unix 上编译。如果你使用它,你不需要任何额外的工具来创建 makefiles/project 文件。
  • @juanchopanza 谢谢! SCons 绝对是我将研究的替代方案。它基于 Python,它是跨平台的,所以它可能对我有用。谢谢!
【解决方案2】:

makefile 的唯一标准是 Posix (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html)。 这不是 Visual Studios 所遵循的,MinGW 是 实际上是 GNU make,它可以选择与 Posix 兼容, 但有大量的扩展。 (我不确定 Eclipse 和 CodeBlocks,但它们可能也使用 GNU make。)

您使用的 makefile 在很大程度上独立于编译器。 Posix 标准品牌是最低品牌;我会推荐 到处使用 GNU make,主要是因为它可移植的,并且 就功能而言,它是最强大的。在另一 手,这并不容易学习(而且我所知道的没有一个是 特别可读)。尽管如此,我还是使用了相同的 GNU makefile 在 Solaris(使用 Sun CC 和 g++)、Linux(使用 g++)和 Windows(使用 MSVC 和 g++)。

关于从 makefile 运行 C++,我也这样做 一直,以及运行 Python 和 shell 脚本。 有两种方法可以做到这一点:

  • 您希望将 C++ 的输出集成到 makefile 本身,GNU make 确实是你唯一的解决方案(我 想想),使用`$(shell ...)`(直到最近我工作的地方, “参考”是 VS 项目文件;我们使用了`$(shell ...)` 调用将项目文件解析为的 Python 脚本 生成目标文件和依赖项列表 生成文件。)
  • 如果要调用 C++ 程序来生成源 后期编译,可以为源码创建依赖 文件: machineGenerated.cpp : somethingElse myPreProcessor myPreProcessor somethingElse > machineGenerated.cpp 您还可以有规则在 生成文件。

我发现在支持多个平台时很有用:

dependsPath       := $(strip $(arch))-$(strip $(syst))-$(strip $(comp))
configPath        := conf/$(dependsPath)
include $(makefilesDir)/$(configPath)/system.mk

通常,我会为我的默认 arch、syst 和 comp(编译器),但我可以在命令行上覆盖它们, 因此在同一台机器上同时使用 g++ 和 VC++ 编译(或 i686x86-64)。

【讨论】:

  • 感谢您的回复。 POSIX 提醒让我重新回到了一起。我真的很感谢你的帮助。现在我正在考虑 Posix,我认为完全放弃 makefile 并寻找更平台中立的东西对我来说会更好。再次感谢!
【解决方案3】:

GNU make 是 POSIX 规范的 make 实现,您可以在这里找到 http://pubs.opengroup.org/onlinepubs/9699919799/ 在“Shell and Utilities”下,搜索“make”。但是你很快就会发现,标准化的 make 部分非常贫乏,不会让你创建非常复杂的 make 环境。这就是为什么 GNU make 具有如此多的附加特性和功能。

此外,Windows 开发人员不太关心 POSIX,尤其是 POSIX 的外壳和实用程序部分。因此,即使您可以将自己限制在该子集,它也不会给您带来太多好处:基本上,跨尚未使用 GNU make 的 POSIX 实例的可移植性(Linux 和 MacOS 默认使用 GNU make)。

您基本上有两个选择:您可以获取一个可以跨多个平台工作的构建工具(例如,GNU make 可以在当今几乎所有可用的操作系统上编译和使用,但还有其他工具,例如 scons ,厨师,胸罩等),或者您可以使用像 cmake 这样的“元工具”,它不会实际构建您的代码,而是会为您想要使用的任何本机构建工具(make、Eclipse、XCode)生成构建控制文件, VisualStudio) 然后您使用该本地构建工具。

【讨论】:

    【解决方案4】:

    答案:没有多平台的 Makefile 标准:取而代之的是使用标准的、多平台的脚本语言,例如 PHP、PERL、Python、(SCons)等,来编译 C++ 项目

    基于其他人都认为他们不是统一标准的 cmets,对更持久、可扩展、跨平台的优雅解决方案的需求对我来说变得更加重要,(此外,我讨厌制作 makefile!)。

    因此,在查看了 Perl、JavaScript、PHP(甚至 Python 脚本)之后,我决定使用 PHP 来构建 C++ 项目。

    我做出这个特殊选择的原因有很多,但主要原因是: 1、PHP工具的数量 2. 通过 Web 界面轻松将其集成到远程构建操作中。 3. Windows、Linux、BSD、OSX 的可移植性。 4. 支持高级逻辑,包括,对于涉及许多嵌套文件夹结构、命名空间和交叉编译的项目。

    PHP 凭借其 shell 脚本支持、跨平台可用性等,是天作之合。

    所以,事不宜迟,这是我刚刚制作的一个小型、快速且肮脏的概念证明。显然它没有“做”任何事情,但它运行/编译得很好,并且很容易看出它在真正的 make 文件中是如何工作的。

    感谢大家的帮助!

    <?php
    
    // Windows cannot "del /files/*.o /S /Q" because it confuses paths for switches.
    // Made my own Variable for Directory Separator for Readability.
    $DS = DIRECTORY_SEPARATOR;
    
    
    // ***********************************************
    // **** Compiler Variables
    // ***** use PHP: include "Config.php", etc
    // ***** to have external variables and functions.
    
    $Compiler   = "mingw32-g++.exe";
    $DebugFlags     = ""; 
    
    $CompilationFlags   = "-std=c++11 -Wall -c -o";
    $LinkFlags      = "-Wall -o";
    
    $IncludeFlags = 
        array(
            "-I".$DS."Includes", 
            "-L".$DS."Redist".$DS."Headers"
        );
    $LibraryLocations =
        array(
            "-L".$DS."Lib",
            "-L".$DS."Redist".$DS."Lib"
        );
    
    // ***********************************************
    // **** Project Properties
    class Project {
        public $Name = "";
        public $Location = ""; 
    
        public function __construct($name="Project", $location="")
        {
            $this->Name = $name;
            $this->Location = $location;
        }
    }
    
    $SubProjects = 
        array(
            new Project("Framework", str_replace("/", $DS, "../Projects/API/Source")) 
            // new Project("Logging", str_replace("/", $DS, "../Projects/Logging/Projects/API/Source"),         
        );
    
    // ***********************************************
    // **** Environment Variables
    $BuildRoot  = "D:".$DS."Build".$DS;
    $ObjectRoot = $BuildRoot + "OBJs".$DS;
    $LibRoot    = $BuildRoot + "LIBs".$DS;
    $RunRoot    = $BuildRoot + "Run".$DS;
    $ConfigRoot = getcwd();
    
    
    
    $directory    = ".".$DS;
    $filterList = array(".", "..");
    $commandOutput = array("");
    $returnValue = 1;
    
    $directoryContents = array_diff(scandir($directory), $filterList);
    
    
    // ***********************************************
    // ***** Main Execution Block
    
    // print_r($SubProjects);
    
    echo PHP_EOL . PHP_EOL;
    echo "***********************************************" . PHP_EOL;
    echo "***** Building: Starting" . PHP_EOL;
    
    ProcessSubProjects($SubProjects);
    echo "***********************************************" . PHP_EOL;
    echo "***** Building: Finished" . PHP_EOL;
    
    
    
    // ***********************************************
    function ProcessSubProjects($subProjects)
    {
        foreach ($subProjects as $project)
        {
            $command = 'dir ' .  realpath($project->Location);
            $commandEcho = array();
    
            // echo $project->Location . PHP_EOL;
            // echo realpath($project->Location) . PHP_EOL;
    
    
            echo PHP_EOL . $command . PHP_EOL . PHP_EOL;
    
            exec ($command, $commandEcho);
            foreach ($commandEcho as $message)
            {
                echo $message . PHP_EOL;
            }
    
        }
    }
    
    
    
    ?> 
    

    【讨论】:

      猜你喜欢
      • 2011-11-10
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      • 2016-02-29
      • 2011-08-04
      • 1970-01-01
      相关资源
      最近更新 更多