Question

I am currently using Visual Studio 2012, Eclipse, CodeBlocks, and MinGW to write C++ 11 code.

Question:

I have noticed features in GCC, (deferred, = vs. immediate, :=, expansions/assignments, etc), and Microsoft's nmake that lead me to wonder what the official "makefile" standard was.

  1. Was there an update to the makefile standards with C++11?
  2. I know where the GNU makefile standard is, (http://www.gnu.org/software/make/manual/make.html), but where can I find "The" makefile standard?
  3. To be honest, I would much rather write makefiles in C++, and run them as scripts from a shell; is there a way to run C++ code as scripts? Perhaps Javascript? What other Scripting Languages are used to do this?

Background:

The difficulty, (*cough), is that I am trying to make sure the code compiles in each environment, as well as trying to cross-compile to other targets as well, (Linux/Ubuntu using OpenGL APIs, Windows 7,8, using DirectX, Android NDK).

One of my core issues is that a lot of the toolsets I am using aren't really "open" to supporting cross platform awesomeness.

Visual Studio 2012: No *nix runnable compiler. Using buggy version of Nov. 2012 C++ CTP Compiler for C++11 support.

GCC 4.7.x/4.8x: Limited to MinGW32 and rough versions of MinGW64.

CMake: Very difficult to get configured correctly, but appears to create makefiles that are specific to GNU, Microsoft, etc. Is there some way to configure this to generate "standard" makefiles?

AutoMake/AutoConf: Appear to only generate GNU compatible makefiles

Was it helpful?

Solution 2

The only standard for makefiles is Posix (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html). This is not followed by Visual Studios, and the MinGW make is actually GNU make, which has an option to be Posix compatible, but has a very large number of extensions. (I'm not sure about Eclipse and CodeBlocks, but they probably use GNU make as well.)

The makefile you use is largely independent of the compiler. The Posix standard make is a minimum make; I would recommend using GNU make everywhere, mainly because it is portable, and it is the most powerful in terms of features. On the other hand, it's not easy to learn (and none of the makes I know are particularly readable). Still, I've used the same GNU makefiles under Solaris (with Sun CC and g++), Linux (with g++) and Windows (with MSVC and g++).

With regards to running C++ from the makefile, I also do this all the time, as well as running Python and shell scripts. There are two ways to do this:

  • You want to integrate the output of your C++ into the makefile itself, GNU make is really your only solution (I think), using `$(shell ... )` (Where I worked until recently, the "reference" was the VS project files; we used `$(shell ...)` to invoke a Python script which parsed the project files to generate the list of target files and dependencies in the makefile.)
  • If you want to invoke a C++ program to generate sources for later compilation, you can create dependencies for the source file:
        machineGenerated.cpp : somethingElse myPreProcessor
                myPreProcessor somethingElse > machineGenerated.cpp
    
    You can also have rules to build `myPreProcessor` in the makefile.

One thing I've found useful when supporting multiple platforms:

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

Normally, I'll set shell variables for my default arch, syst and comp (compiler), but I can override them on the command line, and so compile with both g++ and VC++ on the same machine (or i686 and x86-64).

OTHER TIPS

There is no C++ Standard for make systems. This is purely implementation defined stuff.

For cross-platform work (being both cross-operating system and cross-toolchain), I have found the most popular choice being CMake. I'm not a fan of CMake's syntax or various complexities, and I don't enjoy working with it -- but it does work, and it seems like everybody uses it. CMake skills you gain working on one project will transfer to many others.

Yes, you can get "standard" makefiles out of CMake. This is a function of the generator:

cmake -G "Unix Makefiles" ...

Will generate makefiles compatible with *nix make.

GNU make is an implementation of the POSIX specification for make, which you can find here http://pubs.opengroup.org/onlinepubs/9699919799/ Under "Shell and Utilities", search for "make". However you will quickly discover that the parts of make which are standardized are very anemic and won't let you create very sophisticated make environments. That's why GNU make has so many additional features and capabilities.

Additionally, Windows developers don't care that much about POSIX, and especially not the shell & utilities section of POSIX. So even if you can restrict yourself to that subset it doesn't buy you that much: portability across instances of POSIX which don't already use GNU make, basically (both Linux and MacOS use GNU make by default).

You basically have two choices: you can either get a build tool that will work across multiple platforms (GNU make, for example, can be compiled and used on just about every OS available today, but there are other tools such as scons, cook, bras, etc.), or you can use a "meta-tool" like cmake, which instead of actually building your code it will generate build control files for whatever native build tool you want to use (make, Eclipse, XCode, VisualStudio) then you use that native build tool.

Answer: There is no multi-platform Makefile Standard: Instead, use standard, multi-platform scripting languages, such as PHP, PERL, Python, (SCons), etc, to Compile C++ Projects

Based on everyone else's comments about their not being a unified standard, the need for a more permanent, extensible, cross-platform-aly elegant solution became a lot more important to me, (besides, I loathe making makefiles!).

So, after looking at Perl, JavaScript, PHP, (even Python script), I settled on using PHP to Build C++ Projects.

There are so many reasons I made this particular choice, but the main reasons were: 1. Number of PHP tools 2. Easy integration this into remote build operations via web interfaces. 3. Windows, Linux, BSD, OSX portability. 4. Support for advanced logic, includes, for projects involving many nested folder structures, namespaces, and cross-compilation.

PHP, with its shell scripting support, cross platform availability, etc, is a natural fit.

So, without further ado, here is a small, quick and dirty Proof of Concept I have just made. Obviously it doesn't "do" anything, but it runs/compiles just fine, and how it would work in a real make file is easily seen.

Thanks for all the help!

<?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;
        }

    }
}



?> 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top