В настоящее время я использую Visual Studio 2012, Eclipse, CodeBlocks и MinGW для написания кода C ++ 11.
Вопрос:
Я заметил особенности в GCC (отложенное, = против немедленного,: =, расширения / назначения и т. Д.) И Microsoft nmake, которые заставляют меня задуматься о том, каким был официальный стандарт «make-файла».
Фон:
Сложность (* кашель) заключается в том, что я пытаюсь убедиться, что код компилируется в каждой среде, а также пытаюсь выполнить кросс-компиляцию и для других целей (Linux / Ubuntu с использованием API OpenGL, Windows 7,8, используя DirectX, Android NDK).
Одна из моих основных проблем заключается в том, что многие из используемых мной наборов инструментов на самом деле не «открыты» для поддержки кроссплатформенности.
Visual Studio 2012:
Нет * nix работающего компилятора.
Использование ошибочной версии C ++ CTP Compiler для C ++ 11, ноябрь 2012 г.
GCC 4.7.x / 4.8x:
Ограничено MinGW32 и грубыми версиями MinGW64.
CMake:
Очень трудно правильно настроить, но создается впечатление, что он создает make-файлы, специфичные для GNU, Microsoft и т. Д. Есть ли способ настроить это для генерации «стандартных» make-файлов?
AutoMake / AutoConf:
Появляются только для генерации GNU-совместимых make-файлов
Единственный стандарт для make-файлов — это Posix
(http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html).
Это не сопровождается Visual Studios, и MinGW делает
на самом деле GNU Make, который имеет возможность быть Posix-совместимым,
но имеет очень большое количество расширений. (Я не уверен насчет
Eclipse и CodeBlocks, но они, вероятно, также используют GNU make.)
Используемый вами make-файл в значительной степени не зависит от компилятора.
Стандартная марка Posix — это минимальная марка; Я бы посоветовал
используя GNU make везде, главным образом потому, что является портативный и
это самый мощный с точки зрения возможностей. С другой
рука, это не легко учиться (и ни одна из
особенно читабельно). Тем не менее, я использовал те же файлы сборки GNU
под Solaris (с Sun CC и g ++), Linux (с g ++) и
Windows (с MSVC и g ++).
Что касается запуска C ++ из make-файла, я также делаю это
все время, а также запуск скриптов Python и оболочки.
Есть два способа сделать это:
machineGenerated.cpp: что-то еще myPreProcessor myPreProcessor somethingElse> machineGenerated.cpp
Вы также можете иметь правила для сборки `myPreProcessor` в
Makefile.
Одна вещь, которую я нашел полезной при поддержке нескольких платформ:
dependsPath := $(strip $(arch))-$(strip $(syst))-$(strip $(comp))
configPath := conf/$(dependsPath)
include $(makefilesDir)/$(configPath)/system.mk
Обычно я устанавливаю переменные оболочки для моего значения по умолчанию для arch, syst и
комп (компилятор), но я могу переопределить их в командной строке,
и поэтому скомпилируйте с g ++ и VC ++ на одной машине (или
i686
а также x86-64
).
Не существует стандарта C ++ для систем make. Это чисто реализационные вещи.
Для кросс-платформенной работы (будучи кросс-операционной системой и кросс-цепочкой) я нашел самый популярный выбор: CMake. Я не фанат синтаксиса CMake или различных сложностей, и мне не нравится работать с ним — но он работает, и кажется, что все используют его. Полученные вами навыки работы с CMake над одним проектом будут переданы многим другим.
Да, вы можете получить «стандартные» make-файлы из CMake. Это функция генератора:
cmake -G "Unix Makefiles" ...
Сгенерирует make-файлы, совместимые с * nix make
,
GNU make — это реализация спецификации POSIX для make, которую вы можете найти здесь http://pubs.opengroup.org/onlinepubs/9699919799/ В разделе «Shell and Utilities» найдите «make». Однако вы быстро обнаружите, что стандартизированные части make очень анемичны и не позволят вам создавать очень сложные среды создания. Вот почему GNU make имеет так много дополнительных функций и возможностей.
Кроме того, разработчики Windows не слишком заботятся о POSIX, и особенно не о оболочке. & раздел утилит POSIX. Поэтому, даже если вы можете ограничить себя этим подмножеством, это не так уж и дорого вам: переносимость между экземплярами POSIX, которые еще не используют GNU make, в основном (и Linux, и MacOS используют GNU make по умолчанию).
В основном у вас есть два варианта: вы можете получить инструмент для сборки, который будет работать на нескольких платформах (например, GNU make можно скомпилировать и использовать практически на всех ОС, доступных сегодня, но есть и другие инструменты, такие как scons, cook, бюстгальтеры и т. д.), или вы можете использовать «метаинструмент», такой как cmake, который вместо фактической сборки вашего кода будет генерировать файлы управления сборкой для любого встроенного инструмента сборки, который вы хотите использовать (make, Eclipse, XCode, VisualStudio) тогда вы используете этот родной инструмент для сборки.
Ответ: Не существует многоплатформенного стандарта Makefile: вместо этого используйте стандартные, многоплатформенные языки сценариев, такие как PHP, PERL, Python (SCons) и т. Д., Для компиляции проектов C ++.
Исходя из комментариев всех остальных о том, что они не являются единым стандартом, необходимость в более постоянном, расширяемом, кросс-платформенном элегантном решении стала для меня гораздо важнее (кроме того, я не люблю создавать make-файлы!).
Итак, после изучения Perl, JavaScript, PHP (и даже скрипта Python) я остановился на использовании PHP для сборки проектов C ++.
Есть так много причин, по которым я сделал именно этот выбор, но основными причинами были:
1. Количество инструментов PHP
2. Простая интеграция в операции удаленной сборки через веб-интерфейсы.
3. Переносимость Windows, Linux, BSD, OSX.
4. Поддержка расширенной логики, включая проекты, включающие множество структур вложенных папок, пространства имен и кросс-компиляцию.
PHP с его поддержкой сценариев оболочки, межплатформенной доступностью и т. Д., Естественно.
Итак, без лишних слов, вот небольшое, быстрое и грязное доказательство концепции, которое я только что сделал. Очевидно, что он ничего не «делает», но он прекрасно запускается / компилируется, и легко увидеть, как он будет работать в реальном файле 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;
}
}
}?>