2

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

问题:

我注意到 GCC 中的功能(延迟、= 与立即、:=、扩展/分配等),以及微软的 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

4

4 回答 4

7

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

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

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

cmake -G "Unix Makefiles" ...

将生成与 *nix 兼容的 makefile make

于 2013-05-20T15:49:56.133 回答
4

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

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

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

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

在支持多个平台时,我发现一件事很有用:

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

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

于 2013-05-20T16:27:13.837 回答
1

GNU make 是 make 的 POSIX 规范的实现,您可以在此处找到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、cook、胸罩等),或者您可以使用像 cmake 这样的“元工具”,它不会实际构建您的代码,而是会为您想要使用的任何本机构建工具(make、Eclipse、XCode、VisualStudio)生成构建控制文件然后您使用该本地构建工具。

于 2013-05-20T17:04:03.210 回答
0

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

基于其他人关于他们不是一个统一标准的评论,对我来说,需要一个更永久、可扩展、跨平台的优雅解决方案变得更加重要,(此外,我讨厌制作 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;
        }

    }
}



?> 
于 2013-05-20T20:08:21.087 回答