官方C ++ / 11 Makefile标准/替代品?

时间:2013-05-20 15:45:37

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

我目前正在使用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?还有哪些其他脚本语言可以用来做到这一点?
  4. 背景

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

    我的一个核心问题是,我使用的很多工具集并不是真正“支持”跨平台的“开放”。

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

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

    CMake的: 很难正确配置,但似乎创建特定于GNU,Microsoft等的makefile。有没有办法配置它来生成“标准”makefile?

    AUTOMAKE / AUTOCONF: 似乎只生成GNU兼容的makefile

4 个答案:

答案 0 :(得分:7)

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

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

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

cmake -G "Unix Makefiles" ...

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

答案 1 :(得分:4)

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
    
    你也可以有规则来构建`myPreProcessor` 生成文件。

我支持多个平台时发现有用的东西:

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

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

答案 2 :(得分:1)

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

此外,Windows开发人员并不关心POSIX,尤其是shell和& POSIX的实用程序部分。因此,即使您可以限制自己使用该子集,它也不会为您带来那么多:基本上没有使用GNU make的POSIX实例的可移植性(默认情况下Linux和MacOS都使用GNU make)。

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

答案 3 :(得分:0)

答案: 没有多平台Makefile标准:相反,使用标准的多平台脚本语言,如PHP,PERL,Python,(SCons)等来编译C ++项目< / EM>

基于其他人对其不是统一标准的评论,对我来说,对更加永久,可扩展,跨平台优雅的解决方案的需求变得更加重要(此外,我不喜欢制作文件!)。

因此,在查看了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;
        }

    }
}



?>