2010-11-10 03:56:42 +00:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
*/
2015-04-04 18:45:18 +02:00
# define ENABLE_XCODE
2011-09-03 11:38:50 -04:00
2011-04-08 16:51:15 +02:00
// HACK to allow building with the SDL backend on MinGW
// see bug #1800764 "TOOLS: MinGW tools building broken"
# ifdef main
# undef main
# endif // main
2010-11-10 03:56:42 +00:00
# include "create_project.h"
2020-07-14 09:34:04 +02:00
# include "config.h"
2010-11-23 11:22:31 +00:00
2016-07-02 10:35:29 +02:00
# include "cmake.h"
2011-06-01 17:34:32 -04:00
# include "codeblocks.h"
2020-07-14 09:34:04 +02:00
# include "msbuild.h"
2010-11-10 03:56:42 +00:00
# include "msvc.h"
2010-11-23 11:22:31 +00:00
# include "visualstudio.h"
2011-06-01 17:34:32 -04:00
# include "xcode.h"
2010-11-10 03:56:42 +00:00
2020-07-14 09:34:04 +02:00
# include <algorithm>
2010-11-10 03:56:42 +00:00
# include <fstream>
2020-07-14 09:34:04 +02:00
# include <iomanip>
2010-11-10 03:56:42 +00:00
# include <iostream>
2020-07-14 09:34:04 +02:00
# include <iterator>
2013-09-11 20:36:38 -04:00
# include <sstream>
2010-11-10 03:56:42 +00:00
# include <stack>
2020-07-13 04:00:35 +01:00
# include <utility>
2010-11-10 03:56:42 +00:00
# include <cstdlib>
2020-07-14 09:34:04 +02:00
# include <cstring>
2010-11-10 03:56:42 +00:00
# include <ctime>
2011-04-08 16:51:15 +02:00
# if (defined(_WIN32) || defined(WIN32)) && !defined(__GNUC__)
# define USE_WIN32_API
# endif
2016-07-07 07:49:18 +02:00
# if (defined(_WIN32) || defined(WIN32))
2010-11-10 03:56:42 +00:00
# include <windows.h>
# else
2020-07-14 09:34:04 +02:00
# include <dirent.h>
# include <errno.h>
2010-11-10 03:56:42 +00:00
# include <sstream>
# include <sys/param.h>
# include <sys/stat.h>
# endif
namespace {
/**
* Converts the given path to only use slashes as
* delimiters .
* This means that for example the path :
* foo / bar \ test . txt
* will be converted to :
* foo / bar / test . txt
*
* @ param path Path string .
* @ return Converted path .
*/
std : : string unifyPath ( const std : : string & path ) ;
/**
* Display the help text for the program .
*
* @ param exe Name of the executable .
*/
void displayHelp ( const char * exe ) ;
2016-07-02 10:35:29 +02:00
/**
* Build a list of options to enable or disable GCC warnings
*
* @ param globalWarnings Resulting list of warnings
*/
void addGCCWarnings ( StringList & globalWarnings ) ;
2010-11-10 03:56:42 +00:00
} // End of anonymous namespace
enum ProjectType {
kProjectNone ,
2016-07-02 10:35:29 +02:00
kProjectCMake ,
2010-11-10 03:56:42 +00:00
kProjectCodeBlocks ,
2011-06-01 17:34:32 -04:00
kProjectMSVC ,
kProjectXcode
2010-11-10 03:56:42 +00:00
} ;
int main ( int argc , char * argv [ ] ) {
2011-04-08 16:51:15 +02:00
# ifndef USE_WIN32_API
2010-11-10 03:56:42 +00:00
// Initialize random number generator for UUID creation
2013-07-07 11:23:19 -04:00
std : : srand ( ( unsigned int ) std : : time ( 0 ) ) ;
2010-11-10 03:56:42 +00:00
# endif
if ( argc < 2 ) {
displayHelp ( argv [ 0 ] ) ;
return - 1 ;
}
const std : : string srcDir = argv [ 1 ] ;
BuildSetup setup ;
setup . srcDir = unifyPath ( srcDir ) ;
if ( setup . srcDir . at ( setup . srcDir . size ( ) - 1 ) = = ' / ' )
setup . srcDir . erase ( setup . srcDir . size ( ) - 1 ) ;
setup . filePrefix = setup . srcDir ;
setup . outputDir = ' . ' ;
2013-11-07 12:58:34 +01:00
setup . engines = parseEngines ( setup . srcDir ) ;
2010-11-10 03:56:42 +00:00
if ( setup . engines . empty ( ) ) {
std : : cout < < " WARNING: No engines found in configure file or configure file missing in \" " < < setup . srcDir < < " \" \n " ;
return 0 ;
}
setup . features = getAllFeatures ( ) ;
ProjectType projectType = kProjectNone ;
2020-07-14 09:34:04 +02:00
const MSVCVersion * msvc = NULL ;
2019-04-16 01:09:32 +01:00
int msvcVersion = 0 ;
2010-11-10 03:56:42 +00:00
// Parse command line arguments
using std : : cout ;
for ( int i = 2 ; i < argc ; + + i ) {
if ( ! std : : strcmp ( argv [ i ] , " --list-engines " ) ) {
2011-04-24 13:33:23 -04:00
cout < < " The following enables are available in the " PROJECT_DESCRIPTION " source distribution \n "
2020-07-14 09:34:04 +02:00
< < " located at \" " < < srcDir < < " \" : \n " ;
2010-11-10 03:56:42 +00:00
cout < < " state | name | description \n \n " ;
cout . setf ( std : : ios_base : : left , std : : ios_base : : adjustfield ) ;
for ( EngineDescList : : const_iterator j = setup . engines . begin ( ) ; j ! = setup . engines . end ( ) ; + + j )
cout < < ' ' < < ( j - > enable ? " enabled " : " disabled " ) < < " | " < < std : : setw ( ( std : : streamsize ) 15 ) < < j - > name < < std : : setw ( ( std : : streamsize ) 0 ) < < " | " < < j - > desc < < " \n " ;
cout . setf ( std : : ios_base : : right , std : : ios_base : : adjustfield ) ;
return 0 ;
2016-07-02 10:35:29 +02:00
} else if ( ! std : : strcmp ( argv [ i ] , " --cmake " ) ) {
if ( projectType ! = kProjectNone ) {
std : : cerr < < " ERROR: You cannot pass more than one project type! \n " ;
return - 1 ;
}
projectType = kProjectCMake ;
2010-11-10 03:56:42 +00:00
} else if ( ! std : : strcmp ( argv [ i ] , " --codeblocks " ) ) {
if ( projectType ! = kProjectNone ) {
std : : cerr < < " ERROR: You cannot pass more than one project type! \n " ;
return - 1 ;
}
projectType = kProjectCodeBlocks ;
} else if ( ! std : : strcmp ( argv [ i ] , " --msvc " ) ) {
if ( projectType ! = kProjectNone ) {
std : : cerr < < " ERROR: You cannot pass more than one project type! \n " ;
return - 1 ;
}
projectType = kProjectMSVC ;
2011-09-03 11:38:50 -04:00
# ifdef ENABLE_XCODE
2011-06-01 17:34:32 -04:00
} else if ( ! std : : strcmp ( argv [ i ] , " --xcode " ) ) {
if ( projectType ! = kProjectNone ) {
std : : cerr < < " ERROR: You cannot pass more than one project type! \n " ;
return - 1 ;
}
projectType = kProjectXcode ;
2011-09-03 11:38:50 -04:00
# endif
2011-06-01 17:34:32 -04:00
2010-11-10 03:56:42 +00:00
} else if ( ! std : : strcmp ( argv [ i ] , " --msvc-version " ) ) {
if ( i + 1 > = argc ) {
std : : cerr < < " ERROR: Missing \" version \" parameter for \" --msvc-version \" ! \n " ;
return - 1 ;
}
msvcVersion = atoi ( argv [ + + i ] ) ;
2011-11-20 09:40:17 +00:00
} else if ( ! strncmp ( argv [ i ] , " --enable-engine= " , 16 ) ) {
const char * names = & argv [ i ] [ 16 ] ;
if ( ! * names ) {
std : : cerr < < " ERROR: Invalid command \" " < < argv [ i ] < < " \" \n " ;
return - 1 ;
}
TokenList tokens = tokenize ( names , ' , ' ) ;
TokenList : : const_iterator token = tokens . begin ( ) ;
while ( token ! = tokens . end ( ) ) {
std : : string name = * token + + ;
if ( ! setEngineBuildState ( name , setup . engines , true ) ) {
std : : cerr < < " ERROR: \" " < < name < < " \" is not a known engine! \n " ;
return - 1 ;
}
}
} else if ( ! strncmp ( argv [ i ] , " --disable-engine= " , 17 ) ) {
const char * names = & argv [ i ] [ 17 ] ;
if ( ! * names ) {
std : : cerr < < " ERROR: Invalid command \" " < < argv [ i ] < < " \" \n " ;
return - 1 ;
}
TokenList tokens = tokenize ( names , ' , ' ) ;
TokenList : : const_iterator token = tokens . begin ( ) ;
while ( token ! = tokens . end ( ) ) {
std : : string name = * token + + ;
if ( ! setEngineBuildState ( name , setup . engines , false ) ) {
std : : cerr < < " ERROR: \" " < < name < < " \" is not a known engine! \n " ;
return - 1 ;
}
}
2010-11-10 03:56:42 +00:00
} else if ( ! strncmp ( argv [ i ] , " --enable- " , 9 ) ) {
const char * name = & argv [ i ] [ 9 ] ;
if ( ! * name ) {
std : : cerr < < " ERROR: Invalid command \" " < < argv [ i ] < < " \" \n " ;
return - 1 ;
}
if ( ! std : : strcmp ( name , " all-engines " ) ) {
for ( EngineDescList : : iterator j = setup . engines . begin ( ) ; j ! = setup . engines . end ( ) ; + + j )
j - > enable = true ;
2011-11-20 09:40:17 +00:00
} else if ( ! setFeatureBuildState ( name , setup . features , true ) ) {
std : : cerr < < " ERROR: \" " < < name < < " \" is not a feature! \n " ;
return - 1 ;
2010-11-10 03:56:42 +00:00
}
} else if ( ! strncmp ( argv [ i ] , " --disable- " , 10 ) ) {
const char * name = & argv [ i ] [ 10 ] ;
if ( ! * name ) {
std : : cerr < < " ERROR: Invalid command \" " < < argv [ i ] < < " \" \n " ;
return - 1 ;
}
if ( ! std : : strcmp ( name , " all-engines " ) ) {
for ( EngineDescList : : iterator j = setup . engines . begin ( ) ; j ! = setup . engines . end ( ) ; + + j )
j - > enable = false ;
2011-11-20 09:40:17 +00:00
} else if ( ! setFeatureBuildState ( name , setup . features , false ) ) {
std : : cerr < < " ERROR: \" " < < name < < " \" is not a feature! \n " ;
return - 1 ;
2010-11-10 03:56:42 +00:00
}
} else if ( ! std : : strcmp ( argv [ i ] , " --file-prefix " ) ) {
if ( i + 1 > = argc ) {
std : : cerr < < " ERROR: Missing \" prefix \" parameter for \" --file-prefix \" ! \n " ;
return - 1 ;
}
setup . filePrefix = unifyPath ( argv [ + + i ] ) ;
if ( setup . filePrefix . at ( setup . filePrefix . size ( ) - 1 ) = = ' / ' )
setup . filePrefix . erase ( setup . filePrefix . size ( ) - 1 ) ;
} else if ( ! std : : strcmp ( argv [ i ] , " --output-dir " ) ) {
if ( i + 1 > = argc ) {
2013-07-07 11:23:19 -04:00
std : : cerr < < " ERROR: Missing \" path \" parameter for \" --output-dir \" ! \n " ;
2010-11-10 03:56:42 +00:00
return - 1 ;
}
setup . outputDir = unifyPath ( argv [ + + i ] ) ;
if ( setup . outputDir . at ( setup . outputDir . size ( ) - 1 ) = = ' / ' )
setup . outputDir . erase ( setup . outputDir . size ( ) - 1 ) ;
2010-11-23 11:22:31 +00:00
} else if ( ! std : : strcmp ( argv [ i ] , " --build-events " ) ) {
setup . runBuildEvents = true ;
2011-04-26 20:10:46 -04:00
} else if ( ! std : : strcmp ( argv [ i ] , " --installer " ) ) {
2020-07-14 09:34:04 +02:00
setup . runBuildEvents = true ;
2011-04-26 20:10:46 -04:00
setup . createInstaller = true ;
2011-09-06 16:01:10 -04:00
} else if ( ! std : : strcmp ( argv [ i ] , " --tools " ) ) {
setup . devTools = true ;
2013-07-07 11:23:19 -04:00
} else if ( ! std : : strcmp ( argv [ i ] , " --tests " ) ) {
setup . tests = true ;
2016-08-22 13:09:49 +03:00
} else if ( ! std : : strcmp ( argv [ i ] , " --sdl1 " ) ) {
setup . useSDL2 = false ;
2020-05-08 13:03:57 -07:00
} else if ( ! std : : strcmp ( argv [ i ] , " --use-canonical-lib-names " ) ) {
setup . useCanonicalLibNames = true ;
2010-11-10 03:56:42 +00:00
} else {
std : : cerr < < " ERROR: Unknown parameter \" " < < argv [ i ] < < " \" \n " ;
return - 1 ;
}
}
2013-07-07 11:23:19 -04:00
// When building tests, disable some features
if ( setup . tests ) {
setFeatureBuildState ( " mt32emu " , setup . features , false ) ;
setFeatureBuildState ( " eventrecorder " , setup . features , false ) ;
for ( EngineDescList : : iterator j = setup . engines . begin ( ) ; j ! = setup . engines . end ( ) ; + + j )
j - > enable = false ;
}
2018-05-22 16:03:56 +02:00
2017-02-06 23:18:02 +00:00
// Disable engines for which we are missing dependencies
for ( EngineDescList : : const_iterator i = setup . engines . begin ( ) ; i ! = setup . engines . end ( ) ; + + i ) {
if ( i - > enable ) {
for ( StringList : : const_iterator ef = i - > requiredFeatures . begin ( ) ; ef ! = i - > requiredFeatures . end ( ) ; + + ef ) {
FeatureList : : iterator feature = std : : find ( setup . features . begin ( ) , setup . features . end ( ) , * ef ) ;
if ( feature ! = setup . features . end ( ) & & ! feature - > enable ) {
setEngineBuildState ( i - > name , setup . engines , false ) ;
break ;
}
}
}
}
2013-07-07 11:23:19 -04:00
2018-11-03 23:06:10 +00:00
// HACK: Vorbis and Tremor can not be enabled simultaneously
if ( getFeatureBuildState ( " tremor " , setup . features ) ) {
setFeatureBuildState ( " vorbis " , setup . features , false ) ;
}
2010-11-10 03:56:42 +00:00
// Print status
cout < < " Enabled engines: \n \n " ;
for ( EngineDescList : : const_iterator i = setup . engines . begin ( ) ; i ! = setup . engines . end ( ) ; + + i ) {
if ( i - > enable )
cout < < " " < < i - > desc < < ' \n ' ;
}
cout < < " \n Disabled engines: \n \n " ;
for ( EngineDescList : : const_iterator i = setup . engines . begin ( ) ; i ! = setup . engines . end ( ) ; + + i ) {
if ( ! i - > enable )
cout < < " " < < i - > desc < < ' \n ' ;
}
cout < < " \n Enabled features: \n \n " ;
for ( FeatureList : : const_iterator i = setup . features . begin ( ) ; i ! = setup . features . end ( ) ; + + i ) {
if ( i - > enable )
cout < < " " < < i - > description < < ' \n ' ;
}
cout < < " \n Disabled features: \n \n " ;
for ( FeatureList : : const_iterator i = setup . features . begin ( ) ; i ! = setup . features . end ( ) ; + + i ) {
if ( ! i - > enable )
cout < < " " < < i - > description < < ' \n ' ;
}
2013-07-07 11:23:19 -04:00
// Check if tools and tests are enabled simultaneously
if ( setup . devTools & & setup . tests ) {
std : : cerr < < " ERROR: The tools and tests projects cannot be created simultaneously \n " ;
return - 1 ;
}
2010-11-10 03:56:42 +00:00
// Setup defines and libraries
setup . defines = getEngineDefines ( setup . engines ) ;
setup . libraries = getFeatureLibraries ( setup . features ) ;
// Add features
StringList featureDefines = getFeatureDefines ( setup . features ) ;
setup . defines . splice ( setup . defines . begin ( ) , featureDefines ) ;
2019-07-01 03:06:07 +01:00
bool backendWin32 = false ;
2016-07-02 10:35:29 +02:00
if ( projectType = = kProjectXcode ) {
2015-04-05 01:12:14 +02:00
setup . defines . push_back ( " POSIX " ) ;
2015-12-01 21:02:24 +01:00
// Define both MACOSX, and IPHONE, but only one of them will be associated to the
// correct target by the Xcode project provider.
// This define will help catching up target dependend files, like "browser_osx.mm"
// The suffix ("_osx", or "_ios") will be used by the project provider to filter out
// the files, according to the target.
setup . defines . push_back ( " MACOSX " ) ;
setup . defines . push_back ( " IPHONE " ) ;
2016-07-02 10:35:29 +02:00
} else if ( projectType = = kProjectMSVC | | projectType = = kProjectCodeBlocks ) {
setup . defines . push_back ( " WIN32 " ) ;
2019-07-01 03:06:07 +01:00
backendWin32 = true ;
2016-07-02 10:35:29 +02:00
} else {
// As a last resort, select the backend files to build based on the platform used to build create_project.
// This is broken when cross compiling.
# if defined(_WIN32) || defined(WIN32)
setup . defines . push_back ( " WIN32 " ) ;
2019-07-01 03:06:07 +01:00
backendWin32 = true ;
2016-07-02 10:35:29 +02:00
# else
setup . defines . push_back ( " POSIX " ) ;
# endif
2015-04-04 18:40:50 +02:00
}
2016-05-22 18:52:33 +03:00
2019-07-27 01:06:35 +02:00
bool updatesEnabled = false , curlEnabled = false , sdlnetEnabled = false , ttsEnabled = false ;
2016-05-22 18:52:33 +03:00
for ( FeatureList : : const_iterator i = setup . features . begin ( ) ; i ! = setup . features . end ( ) ; + + i ) {
2016-10-20 21:00:32 -04:00
if ( i - > enable ) {
2019-12-16 01:03:06 +00:00
if ( ! updatesEnabled & & ! strcmp ( i - > name , " updates " ) )
2016-10-20 21:00:32 -04:00
updatesEnabled = true ;
2019-12-16 01:03:06 +00:00
else if ( ! curlEnabled & & ! strcmp ( i - > name , " libcurl " ) )
2016-10-20 21:00:32 -04:00
curlEnabled = true ;
2019-12-16 01:03:06 +00:00
else if ( ! sdlnetEnabled & & ! strcmp ( i - > name , " sdlnet " ) )
2016-10-20 21:00:32 -04:00
sdlnetEnabled = true ;
2019-12-16 01:03:06 +00:00
else if ( ! ttsEnabled & & ! strcmp ( i - > name , " tts " ) )
2019-07-27 01:06:35 +02:00
ttsEnabled = true ;
2016-10-20 21:00:32 -04:00
}
2016-05-22 18:52:33 +03:00
}
2016-10-20 21:00:32 -04:00
2016-05-22 18:52:33 +03:00
if ( updatesEnabled ) {
setup . defines . push_back ( " USE_SPARKLE " ) ;
2019-07-01 03:06:07 +01:00
if ( backendWin32 )
2016-05-22 18:52:33 +03:00
setup . libraries . push_back ( " winsparkle " ) ;
else
setup . libraries . push_back ( " sparkle " ) ;
}
2019-07-01 03:06:07 +01:00
if ( backendWin32 ) {
2019-07-01 02:50:34 +01:00
if ( curlEnabled ) {
setup . defines . push_back ( " CURL_STATICLIB " ) ;
setup . libraries . push_back ( " ws2_32 " ) ;
setup . libraries . push_back ( " wldap32 " ) ;
setup . libraries . push_back ( " crypt32 " ) ;
setup . libraries . push_back ( " normaliz " ) ;
}
if ( sdlnetEnabled ) {
setup . libraries . push_back ( " iphlpapi " ) ;
}
2019-12-16 01:03:06 +00:00
if ( ttsEnabled ) {
setup . libraries . push_back ( " sapi " ) ;
}
2019-07-01 03:06:07 +01:00
setup . libraries . push_back ( " winmm " ) ;
2019-07-01 02:50:34 +01:00
}
2016-10-20 21:00:32 -04:00
2010-11-10 03:56:42 +00:00
setup . defines . push_back ( " SDL_BACKEND " ) ;
2016-03-24 01:26:05 +01:00
if ( ! setup . useSDL2 ) {
cout < < " \n Building against SDL 1.2 \n \n " ;
2015-03-06 02:39:57 +02:00
setup . libraries . push_back ( " sdl " ) ;
} else {
2016-03-24 01:26:05 +01:00
cout < < " \n Building against SDL 2.0 \n \n " ;
// TODO: This also defines USE_SDL2 in the preprocessor, we don't do
// this in our configure/make based build system. Adapt create_project
// to replicate this behavior.
setup . defines . push_back ( " USE_SDL2 " ) ;
2015-03-06 02:39:57 +02:00
setup . libraries . push_back ( " sdl2 " ) ;
}
2010-11-10 03:56:42 +00:00
2020-05-08 13:03:57 -07:00
if ( setup . useCanonicalLibNames ) {
2020-05-14 20:49:50 +02:00
for ( StringList : : iterator lib = setup . libraries . begin ( ) ; lib ! = setup . libraries . end ( ) ; + + lib ) {
* lib = getCanonicalLibName ( * lib ) ;
2020-05-08 13:03:57 -07:00
}
}
2011-04-24 13:33:23 -04:00
// Add additional project-specific library
# ifdef ADDITIONAL_LIBRARY
setup . libraries . push_back ( ADDITIONAL_LIBRARY ) ;
# endif
2010-11-10 03:56:42 +00:00
// List of global warnings and map of project-specific warnings
2011-04-28 16:45:54 +02:00
// FIXME: As shown below these two structures have different behavior for
// Code::Blocks and MSVC. In Code::Blocks this is used to enable *and*
// disable certain warnings (and some other not warning related flags
// actually...). While in MSVC this is solely for disabling warnings.
// That is really not nice. We should consider a nicer way of doing this.
2010-11-10 03:56:42 +00:00
StringList globalWarnings ;
std : : map < std : : string , StringList > projectWarnings ;
CreateProjectTool : : ProjectProvider * provider = NULL ;
switch ( projectType ) {
default :
case kProjectNone :
std : : cerr < < " ERROR: No project type has been specified! \n " ;
return - 1 ;
2016-07-02 10:35:29 +02:00
case kProjectCMake :
if ( setup . devTools | | setup . tests ) {
std : : cerr < < " ERROR: Building tools or tests is not supported for the CMake project type! \n " ;
return - 1 ;
}
addGCCWarnings ( globalWarnings ) ;
provider = new CreateProjectTool : : CMakeProvider ( globalWarnings , projectWarnings ) ;
break ;
2010-11-10 03:56:42 +00:00
case kProjectCodeBlocks :
2013-07-07 11:23:19 -04:00
if ( setup . devTools | | setup . tests ) {
std : : cerr < < " ERROR: Building tools or tests is not supported for the CodeBlocks project type! \n " ;
2011-09-06 16:01:10 -04:00
return - 1 ;
}
2016-07-02 10:35:29 +02:00
addGCCWarnings ( globalWarnings ) ;
2010-11-10 03:56:42 +00:00
provider = new CreateProjectTool : : CodeBlocksProvider ( globalWarnings , projectWarnings ) ;
2011-04-26 13:31:13 -04:00
// Those libraries are automatically added by MSVC, but we need to add them manually with mingw
setup . libraries . push_back ( " ole32 " ) ;
setup . libraries . push_back ( " uuid " ) ;
2010-11-10 03:56:42 +00:00
break ;
case kProjectMSVC :
2019-04-16 01:09:32 +01:00
// Auto-detect if no version is specified
if ( msvcVersion = = 0 ) {
msvcVersion = getInstalledMSVC ( ) ;
if ( msvcVersion = = 0 ) {
std : : cerr < < " ERROR: No Visual Studio versions found, please specify one with \" --msvc-version \" \n " ;
return - 1 ;
} else {
cout < < " Visual Studio " < < msvcVersion < < " detected \n \n " ;
}
}
2019-04-15 18:59:00 +01:00
msvc = getMSVCVersion ( msvcVersion ) ;
if ( ! msvc ) {
std : : cerr < < " ERROR: Unsupported version: \" " < < msvcVersion < < " \" passed to \" --msvc-version \" ! \n " ;
return - 1 ;
}
2010-11-10 03:56:42 +00:00
////////////////////////////////////////////////////////////////////////////
// For Visual Studio, all warnings are on by default in the project files,
// so we pass a list of warnings to disable globally or per-project
//
////////////////////////////////////////////////////////////////////////////
//
// 4068 (unknown pragma)
// only used in scumm engine to mark code sections
//
// 4100 (unreferenced formal parameter)
//
// 4103 (alignment changed after including header, may be due to missing #pragma pack(pop))
// used by pack-start / pack-end
//
// 4127 (conditional expression is constant)
// used in a lot of engines
//
// 4244 ('conversion' conversion from 'type1' to 'type2', possible loss of data)
// throws tons and tons of warnings, most of them false positives
//
// 4250 ('class1' : inherits 'class2::member' via dominance)
// two or more members have the same name. Should be harmless
//
2015-09-28 19:23:58 -04:00
// 4267 ('var' : conversion from 'size_t' to 'type', possible loss of data)
// throws tons and tons of warnings (no immediate plan to fix all usages)
//
2010-11-10 03:56:42 +00:00
// 4310 (cast truncates constant value)
// used in some engines
//
2011-11-17 19:45:53 +02:00
// 4345 (behavior change: an object of POD type constructed with an
// initializer of the form () will be default-initialized)
// used in Common::Array(), and it basically means that newer VS
// versions adhere to the standard in this case. Can be safely
// disabled.
//
2010-11-10 03:56:42 +00:00
// 4351 (new behavior: elements of array 'array' will be default initialized)
// a change in behavior in Visual Studio 2005. We want the new behavior, so it can be disabled
//
// 4512 ('class' : assignment operator could not be generated)
// some classes use const items and the default assignment operator cannot be generated
//
2015-10-12 14:39:28 -04:00
// 4577 ('noexcept' used with no exception handling mode specified)
//
2010-11-10 03:56:42 +00:00
// 4702 (unreachable code)
// mostly thrown after error() calls (marked as NORETURN)
//
// 4706 (assignment within conditional expression)
// used in a lot of engines
//
// 4800 ('type' : forcing value to bool 'true' or 'false' (performance warning))
//
// 4996 ('function': was declared deprecated)
// disabling it removes all the non-standard unsafe functions warnings (strcpy_s, etc.)
//
// 6211 (Leaking memory <pointer> due to an exception. Consider using a local catch block to clean up memory)
// we disable exceptions
//
// 6204 (possible buffer overrun in call to <function>: use of unchecked parameter <variable>)
// 6385 (invalid data: accessing <buffer name>, the readable size is <size1> bytes, but <size2> bytes may be read)
// 6386 (buffer overrun: accessing <buffer name>, the writable size is <size1> bytes, but <size2> bytes may be written)
// give way too many false positives
//
////////////////////////////////////////////////////////////////////////////
//
// 4189 (local variable is initialized but not referenced)
// false positive in lure engine
//
// 4355 ('this' : used in base member initializer list)
// only disabled for specific engines where it is used in a safe way
//
2016-08-12 20:18:20 -04:00
// 4373 (previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers)
//
2010-11-10 03:56:42 +00:00
// 4510 ('class' : default constructor could not be generated)
//
// 4511 ('class' : copy constructor could not be generated)
//
// 4610 (object 'class' can never be instantiated - user-defined constructor required)
// "correct" but harmless (as is 4510)
//
////////////////////////////////////////////////////////////////////////////
2011-04-28 16:42:16 +02:00
globalWarnings . push_back ( " 4068 " ) ;
globalWarnings . push_back ( " 4100 " ) ;
globalWarnings . push_back ( " 4103 " ) ;
globalWarnings . push_back ( " 4127 " ) ;
globalWarnings . push_back ( " 4244 " ) ;
globalWarnings . push_back ( " 4250 " ) ;
globalWarnings . push_back ( " 4310 " ) ;
2011-11-17 19:45:53 +02:00
globalWarnings . push_back ( " 4345 " ) ;
2011-04-28 16:42:16 +02:00
globalWarnings . push_back ( " 4351 " ) ;
globalWarnings . push_back ( " 4512 " ) ;
globalWarnings . push_back ( " 4702 " ) ;
globalWarnings . push_back ( " 4706 " ) ;
globalWarnings . push_back ( " 4800 " ) ;
globalWarnings . push_back ( " 4996 " ) ;
globalWarnings . push_back ( " 6204 " ) ;
globalWarnings . push_back ( " 6211 " ) ;
globalWarnings . push_back ( " 6385 " ) ;
globalWarnings . push_back ( " 6386 " ) ;
2019-04-15 18:59:00 +01:00
if ( msvcVersion > = 14 ) {
2015-10-12 14:39:28 -04:00
globalWarnings . push_back ( " 4267 " ) ;
globalWarnings . push_back ( " 4577 " ) ;
}
2011-04-28 16:42:16 +02:00
projectWarnings [ " agi " ] . push_back ( " 4510 " ) ;
projectWarnings [ " agi " ] . push_back ( " 4610 " ) ;
projectWarnings [ " agos " ] . push_back ( " 4511 " ) ;
2011-11-17 19:45:53 +02:00
projectWarnings [ " dreamweb " ] . push_back ( " 4355 " ) ;
2012-09-05 07:54:33 -04:00
2011-04-28 16:42:16 +02:00
projectWarnings [ " lure " ] . push_back ( " 4189 " ) ;
projectWarnings [ " lure " ] . push_back ( " 4355 " ) ;
projectWarnings [ " kyra " ] . push_back ( " 4355 " ) ;
2011-12-28 05:12:43 +02:00
projectWarnings [ " kyra " ] . push_back ( " 4510 " ) ;
projectWarnings [ " kyra " ] . push_back ( " 4610 " ) ;
2011-04-28 16:42:16 +02:00
projectWarnings [ " m4 " ] . push_back ( " 4355 " ) ;
2010-11-10 03:56:42 +00:00
2016-08-12 20:18:20 -04:00
projectWarnings [ " sci " ] . push_back ( " 4373 " ) ;
2014-06-19 18:21:14 -07:00
if ( msvcVersion = = 9 )
2019-04-15 18:59:00 +01:00
provider = new CreateProjectTool : : VisualStudioProvider ( globalWarnings , projectWarnings , msvcVersion , * msvc ) ;
2010-11-10 03:56:42 +00:00
else
2019-04-15 18:59:00 +01:00
provider = new CreateProjectTool : : MSBuildProvider ( globalWarnings , projectWarnings , msvcVersion , * msvc ) ;
2010-11-10 03:56:42 +00:00
break ;
2011-06-01 17:34:32 -04:00
case kProjectXcode :
2013-07-07 11:23:19 -04:00
if ( setup . devTools | | setup . tests ) {
std : : cerr < < " ERROR: Building tools or tests is not supported for the XCode project type! \n " ;
2011-09-06 16:01:10 -04:00
return - 1 ;
}
2011-06-01 17:34:32 -04:00
////////////////////////////////////////////////////////////////////////////
// Xcode is also using GCC behind the scenes. See Code::Blocks comment
// for info on all warnings
////////////////////////////////////////////////////////////////////////////
globalWarnings . push_back ( " -Wall " ) ;
globalWarnings . push_back ( " -Wno-long-long " ) ;
globalWarnings . push_back ( " -Wno-multichar " ) ;
globalWarnings . push_back ( " -Wno-unknown-pragmas " ) ;
globalWarnings . push_back ( " -Wno-reorder " ) ;
globalWarnings . push_back ( " -Wpointer-arith " ) ;
globalWarnings . push_back ( " -Wcast-qual " ) ;
globalWarnings . push_back ( " -Wcast-align " ) ;
globalWarnings . push_back ( " -Wshadow " ) ;
globalWarnings . push_back ( " -Wimplicit " ) ;
globalWarnings . push_back ( " -Wnon-virtual-dtor " ) ;
globalWarnings . push_back ( " -Wwrite-strings " ) ;
// The following are not warnings at all... We should consider adding them to
// a different list of parameters.
2012-04-17 14:45:22 +02:00
# if !NEEDS_RTTI
2011-06-01 17:34:32 -04:00
globalWarnings . push_back ( " -fno-rtti " ) ;
2012-04-17 14:45:22 +02:00
# endif
2011-06-01 17:34:32 -04:00
globalWarnings . push_back ( " -fno-exceptions " ) ;
globalWarnings . push_back ( " -fcheck-new " ) ;
2015-07-20 00:53:10 +03:00
provider = new CreateProjectTool : : XcodeProvider ( globalWarnings , projectWarnings ) ;
2011-06-01 17:34:32 -04:00
break ;
2010-11-10 03:56:42 +00:00
}
2011-09-06 16:01:10 -04:00
// Setup project name and description
2020-07-14 09:34:04 +02:00
setup . projectName = PROJECT_NAME ;
2011-09-06 16:01:10 -04:00
setup . projectDescription = PROJECT_DESCRIPTION ;
if ( setup . devTools ) {
2020-07-14 09:34:04 +02:00
setup . projectName + = " -tools " ;
2011-09-06 16:01:10 -04:00
setup . projectDescription + = " Tools " ;
}
2013-07-07 11:23:19 -04:00
if ( setup . tests ) {
setup . projectName + = " -tests " ;
setup . projectDescription + = " Tests " ;
}
2010-11-10 03:56:42 +00:00
provider - > createProject ( setup ) ;
delete provider ;
}
namespace {
std : : string unifyPath ( const std : : string & path ) {
std : : string result = path ;
std : : replace ( result . begin ( ) , result . end ( ) , ' \\ ' , ' / ' ) ;
return result ;
}
void displayHelp ( const char * exe ) {
using std : : cout ;
cout < < " Usage: \n "
< < exe < < " path \\ to \\ source [optional options] \n "
< < " \n "
2011-04-24 13:33:23 -04:00
< < " Creates project files for the " PROJECT_DESCRIPTION " source located at \" path \\ to \\ source \" . \n "
2010-11-10 03:56:42 +00:00
" The project files will be created in the directory where tool is run from and \n "
" will include \" path \\ to \\ source \" for relative file paths, thus be sure that you \n "
" pass a relative file path like \" .. \\ .. \\ trunk \" . \n "
" \n "
" Additionally there are the following switches for changing various settings: \n "
" \n "
" Project specific settings: \n "
2020-05-08 13:03:57 -07:00
" --cmake build CMake project files \n "
" --codeblocks build Code::Blocks project files \n "
" --msvc build Visual Studio project files \n "
" --xcode build XCode project files \n "
" --file-prefix prefix allow overwriting of relative file prefix in the \n "
" MSVC project files. By default the prefix is the \n "
" \" path \\ to \\ source \" argument \n "
" --output-dir path overwrite path, where the project files are placed \n "
" By default this is \" . \" , i.e. the current working \n "
" directory \n "
2010-11-10 03:56:42 +00:00
" \n "
" MSVC specific settings: \n "
2020-05-08 13:03:57 -07:00
" --msvc-version version set the targeted MSVC version. Possible values: \n " ;
2019-04-15 18:59:00 +01:00
const MSVCList msvc = getAllMSVCVersions ( ) ;
for ( MSVCList : : const_iterator i = msvc . begin ( ) ; i ! = msvc . end ( ) ; + + i )
cout < < " " < < i - > version < < " stands for \" " < < i - > name < < " \" \n " ;
2020-05-08 13:03:57 -07:00
cout < < " If no version is set, the latest installed version is used \n "
" --build-events Run custom build events as part of the build \n "
" (default: false) \n "
" --installer Create installer after the build (implies --build-events) \n "
" (default: false) \n "
" --tools Create project files for the devtools \n "
" (ignores --build-events and --installer, as well as engine settings) \n "
" (default: false) \n "
" --tests Create project files for the tests \n "
" (ignores --build-events and --installer, as well as engine settings) \n "
" (default: false) \n "
2020-05-14 20:49:50 +02:00
" --use-canonical-lib-names Use canonical library names for linking. This makes it easy to use \n "
" e.g. vcpkg-provided libraries \n "
2020-05-08 13:03:57 -07:00
" (default: false) \n "
2010-11-10 03:56:42 +00:00
" \n "
2011-04-24 13:33:23 -04:00
" Engines settings: \n "
2020-05-08 13:03:57 -07:00
" --list-engines list all available engines and their default state \n "
" --enable-engine=<name> enable building of the engine with the name \" name \" \n "
" --disable-engine=<name> disable building of the engine with the name \" name \" \n "
" --enable-all-engines enable building of all engines \n "
" --disable-all-engines disable building of all engines \n "
2010-11-10 03:56:42 +00:00
" \n "
2011-04-24 13:33:23 -04:00
" Optional features settings: \n "
2020-05-08 13:03:57 -07:00
" --enable-<name> enable inclusion of the feature \" name \" \n "
" --disable-<name> disable inclusion of the feature \" name \" \n "
2015-09-28 19:23:58 -04:00
" \n "
" SDL settings: \n "
2020-05-08 13:03:57 -07:00
" --sdl1 link to SDL 1.2, instead of SDL 2.0 \n "
2010-11-10 03:56:42 +00:00
" \n "
" There are the following features available: \n "
" \n " ;
cout < < " state | name | description \n \n " ;
const FeatureList features = getAllFeatures ( ) ;
cout . setf ( std : : ios_base : : left , std : : ios_base : : adjustfield ) ;
for ( FeatureList : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; + + i )
cout < < ' ' < < ( i - > enable ? " enabled " : " disabled " ) < < " | " < < std : : setw ( ( std : : streamsize ) 15 ) < < i - > name < < std : : setw ( ( std : : streamsize ) 0 ) < < " | " < < i - > description < < ' \n ' ;
cout . setf ( std : : ios_base : : right , std : : ios_base : : adjustfield ) ;
}
2016-07-02 10:35:29 +02:00
void addGCCWarnings ( StringList & globalWarnings ) {
////////////////////////////////////////////////////////////////////////////
//
// -Wall
// enable all warnings
//
// -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
// disable annoying and not-so-useful warnings
//
// -Wpointer-arith -Wcast-qual -Wcast-align
// -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
// enable even more warnings...
//
// -fno-exceptions -fcheck-new
// disable exceptions, and enable checking of pointers returned by "new"
//
////////////////////////////////////////////////////////////////////////////
globalWarnings . push_back ( " -Wall " ) ;
globalWarnings . push_back ( " -Wno-long-long " ) ;
globalWarnings . push_back ( " -Wno-multichar " ) ;
globalWarnings . push_back ( " -Wno-unknown-pragmas " ) ;
globalWarnings . push_back ( " -Wno-reorder " ) ;
globalWarnings . push_back ( " -Wpointer-arith " ) ;
globalWarnings . push_back ( " -Wcast-qual " ) ;
globalWarnings . push_back ( " -Wcast-align " ) ;
globalWarnings . push_back ( " -Wshadow " ) ;
globalWarnings . push_back ( " -Wnon-virtual-dtor " ) ;
globalWarnings . push_back ( " -Wwrite-strings " ) ;
// The following are not warnings at all... We should consider adding them to
// a different list of parameters.
globalWarnings . push_back ( " -fno-exceptions " ) ;
globalWarnings . push_back ( " -fcheck-new " ) ;
}
2010-11-10 03:56:42 +00:00
/**
2013-11-07 12:58:34 +01:00
* Parse the configure . engine file of a given engine directory and return a
* list of all defined engines .
2010-11-10 03:56:42 +00:00
*
2013-11-07 12:58:34 +01:00
* @ param engineDir The directory of the engine .
* @ return The list of all defined engines .
*/
EngineDescList parseEngineConfigure ( const std : : string & engineDir ) ;
/**
* Compares two FSNode entries in a strict - weak fashion based on the name .
2010-11-10 03:56:42 +00:00
*
2013-11-07 12:58:34 +01:00
* @ param left The first operand .
* @ param right The second operand .
* @ return " true " when the name of the left operand is strictly smaller than
* the name of the second operand . " false " otherwise .
2010-11-10 03:56:42 +00:00
*/
2013-11-07 12:58:34 +01:00
bool compareFSNode ( const CreateProjectTool : : FSNode & left , const CreateProjectTool : : FSNode & right ) ;
2013-11-07 12:58:35 +01:00
# ifdef FIRST_ENGINE
/**
* Compares two FSNode entries in a strict - weak fashion based on engine name
* order .
*
* @ param left The first operand .
* @ param right The second operand .
* @ return " true " when the name of the left operand is strictly smaller than
* the name of the second operand . " false " otherwise .
*/
bool compareEngineNames ( const CreateProjectTool : : FSNode & left , const CreateProjectTool : : FSNode & right ) ;
# endif
2010-11-10 03:56:42 +00:00
} // End of anonymous namespace
2013-11-07 12:58:34 +01:00
EngineDescList parseEngines ( const std : : string & srcDir ) {
using CreateProjectTool : : FileList ;
using CreateProjectTool : : listDirectory ;
2010-11-10 03:56:42 +00:00
2013-11-07 12:58:34 +01:00
EngineDescList engineList ;
2010-11-10 03:56:42 +00:00
2013-11-07 12:58:34 +01:00
FileList engineFiles = listDirectory ( srcDir + " /engines/ " ) ;
2010-11-10 03:56:42 +00:00
2013-11-07 12:58:35 +01:00
# ifdef FIRST_ENGINE
// In case we want to sort an engine to the front of the list we will
// use some manual sorting predicate which assures that.
engineFiles . sort ( & compareEngineNames ) ;
# else
// Otherwise, we simply sort the file list alphabetically this allows
// for a nicer order in --list-engines output, for example.
2013-11-07 12:58:34 +01:00
engineFiles . sort ( & compareFSNode ) ;
2013-11-07 12:58:35 +01:00
# endif
2010-11-10 03:56:42 +00:00
2013-11-07 12:58:34 +01:00
for ( FileList : : const_iterator i = engineFiles . begin ( ) , end = engineFiles . end ( ) ; i ! = end ; + + i ) {
// Each engine requires its own sub directory thus we will skip all
// non directory file nodes here.
if ( ! i - > isDirectory ) {
continue ;
}
2010-11-10 03:56:42 +00:00
2013-11-07 12:58:34 +01:00
// Retrieve all engines defined in this sub directory and add them to
// the list of all engines.
EngineDescList list = parseEngineConfigure ( srcDir + " /engines/ " + i - > name ) ;
engineList . splice ( engineList . end ( ) , list ) ;
2010-11-10 03:56:42 +00:00
}
2013-11-07 12:58:34 +01:00
return engineList ;
2010-11-10 03:56:42 +00:00
}
bool isSubEngine ( const std : : string & name , const EngineDescList & engines ) {
for ( EngineDescList : : const_iterator i = engines . begin ( ) ; i ! = engines . end ( ) ; + + i ) {
if ( std : : find ( i - > subEngines . begin ( ) , i - > subEngines . end ( ) , name ) ! = i - > subEngines . end ( ) )
return true ;
}
return false ;
}
bool setEngineBuildState ( const std : : string & name , EngineDescList & engines , bool enable ) {
if ( enable & & isSubEngine ( name , engines ) ) {
// When we enable a sub engine, we need to assure that the parent is also enabled,
// thus we enable both sub engine and parent over here.
EngineDescList : : iterator engine = std : : find ( engines . begin ( ) , engines . end ( ) , name ) ;
if ( engine ! = engines . end ( ) ) {
engine - > enable = enable ;
for ( engine = engines . begin ( ) ; engine ! = engines . end ( ) ; + + engine ) {
if ( std : : find ( engine - > subEngines . begin ( ) , engine - > subEngines . end ( ) , name ) ! = engine - > subEngines . end ( ) ) {
engine - > enable = true ;
break ;
}
}
return true ;
}
} else {
EngineDescList : : iterator engine = std : : find ( engines . begin ( ) , engines . end ( ) , name ) ;
if ( engine ! = engines . end ( ) ) {
engine - > enable = enable ;
2011-05-29 19:29:01 +03:00
// When we disable an engine, we also need to disable all the sub engines.
2010-11-10 03:56:42 +00:00
if ( ! enable & & ! engine - > subEngines . empty ( ) ) {
for ( StringList : : const_iterator j = engine - > subEngines . begin ( ) ; j ! = engine - > subEngines . end ( ) ; + + j ) {
EngineDescList : : iterator subEngine = std : : find ( engines . begin ( ) , engines . end ( ) , * j ) ;
if ( subEngine ! = engines . end ( ) )
subEngine - > enable = false ;
}
}
return true ;
}
}
return false ;
}
StringList getEngineDefines ( const EngineDescList & engines ) {
StringList result ;
for ( EngineDescList : : const_iterator i = engines . begin ( ) ; i ! = engines . end ( ) ; + + i ) {
if ( i - > enable ) {
std : : string define = " ENABLE_ " + i - > name ;
std : : transform ( define . begin ( ) , define . end ( ) , define . begin ( ) , toupper ) ;
result . push_back ( define ) ;
}
}
return result ;
}
namespace {
2013-11-07 12:58:34 +01:00
/**
* Try to parse a given line and create an engine definition
* out of the result .
*
* This may take * any * input line , when the line is not used
* to define an engine the result of the function will be " false " .
*
* Note that the contents of " engine " are undefined , when this
* function returns " false " .
*
* @ param line Text input line .
* @ param engine Reference to an object , where the engine information
* is to be stored in .
* @ return " true " , when parsing succeeded , " false " otherwise .
*/
2010-11-10 03:56:42 +00:00
bool parseEngine ( const std : : string & line , EngineDesc & engine ) {
// Format:
2017-02-06 23:18:02 +00:00
// add_engine engine_name "Readable Description" enable_default ["SubEngineList"] ["base games"] ["dependencies"]
2010-11-10 03:56:42 +00:00
TokenList tokens = tokenize ( line ) ;
if ( tokens . size ( ) < 4 )
return false ;
TokenList : : const_iterator token = tokens . begin ( ) ;
if ( * token ! = " add_engine " )
return false ;
+ + token ;
2020-07-14 09:34:04 +02:00
engine . name = * token ;
+ + token ;
engine . desc = * token ;
+ + token ;
engine . enable = ( * token = = " yes " ) ;
+ + token ;
2017-02-06 23:18:02 +00:00
if ( token ! = tokens . end ( ) ) {
2010-11-10 03:56:42 +00:00
engine . subEngines = tokenize ( * token ) ;
2017-02-06 23:18:02 +00:00
+ + token ;
if ( token ! = tokens . end ( ) )
+ + token ;
if ( token ! = tokens . end ( ) )
engine . requiredFeatures = tokenize ( * token ) ;
}
2010-11-10 03:56:42 +00:00
return true ;
}
2013-11-07 12:58:34 +01:00
EngineDescList parseEngineConfigure ( const std : : string & engineDir ) {
std : : string configureFile = engineDir + " /configure.engine " ;
std : : ifstream configure ( configureFile . c_str ( ) ) ;
if ( ! configure )
return EngineDescList ( ) ;
std : : string line ;
EngineDescList engines ;
for ( ; ; ) {
std : : getline ( configure , line ) ;
if ( configure . eof ( ) )
break ;
if ( configure . fail ( ) )
error ( " Failed while reading from " + configureFile ) ;
EngineDesc desc ;
if ( parseEngine ( line , desc ) )
engines . push_back ( desc ) ;
}
return engines ;
}
bool compareFSNode ( const CreateProjectTool : : FSNode & left , const CreateProjectTool : : FSNode & right ) {
return left . name < right . name ;
}
2013-11-07 12:58:35 +01:00
# ifdef FIRST_ENGINE
bool compareEngineNames ( const CreateProjectTool : : FSNode & left , const CreateProjectTool : : FSNode & right ) {
if ( left . name = = FIRST_ENGINE ) {
return right . name ! = FIRST_ENGINE ;
} else if ( right . name = = FIRST_ENGINE ) {
return false ;
} else {
return compareFSNode ( left , right ) ;
}
}
# endif
2012-09-05 07:54:33 -04:00
} // End of anonymous namespace
2010-11-10 03:56:42 +00:00
2011-11-20 09:40:17 +00:00
TokenList tokenize ( const std : : string & input , char separator ) {
2010-11-10 03:56:42 +00:00
TokenList result ;
std : : string : : size_type sIdx = input . find_first_not_of ( " \t " ) ;
std : : string : : size_type nIdx = std : : string : : npos ;
if ( sIdx = = std : : string : : npos )
return result ;
do {
if ( input . at ( sIdx ) = = ' \" ' ) {
+ + sIdx ;
nIdx = input . find_first_of ( ' \" ' , sIdx ) ;
} else {
2011-11-20 09:40:17 +00:00
nIdx = input . find_first_of ( separator , sIdx ) ;
2010-11-10 03:56:42 +00:00
}
if ( nIdx ! = std : : string : : npos ) {
result . push_back ( input . substr ( sIdx , nIdx - sIdx ) ) ;
2011-11-20 09:40:17 +00:00
if ( separator = = ' ' )
sIdx = input . find_first_not_of ( " \t " , nIdx + 1 ) ;
else
sIdx = input . find_first_not_of ( separator , nIdx + 1 ) ;
2010-11-10 03:56:42 +00:00
} else {
result . push_back ( input . substr ( sIdx ) ) ;
break ;
}
} while ( sIdx ! = std : : string : : npos ) ;
return result ;
}
namespace {
2020-07-14 09:34:04 +02:00
// clang-format off
2010-11-10 03:56:42 +00:00
const Feature s_features [ ] = {
// Libraries
2016-05-22 16:10:11 +03:00
{ " libz " , " USE_ZLIB " , " zlib " , true , " zlib (compression) support " } ,
{ " mad " , " USE_MAD " , " libmad " , true , " libmad (MP3) support " } ,
2020-04-30 14:22:10 +03:00
{ " fribidi " , " USE_FRIBIDI " , " fribidi " , true , " BiDi support " } ,
2018-11-03 23:06:10 +00:00
{ " ogg " , " USE_OGG " , " libogg_static " , true , " Ogg support " } ,
{ " vorbis " , " USE_VORBIS " , " libvorbisfile_static libvorbis_static " , true , " Vorbis support " } ,
{ " tremor " , " USE_TREMOR " , " libtremor " , false , " Tremor support " } ,
2015-12-11 14:24:29 +01:00
{ " flac " , " USE_FLAC " , " libFLAC_static win_utf8_io_static " , true , " FLAC support " } ,
2016-05-22 16:10:11 +03:00
{ " png " , " USE_PNG " , " libpng16 " , true , " libpng support " } ,
2015-12-11 14:24:29 +01:00
{ " faad " , " USE_FAAD " , " libfaad " , false , " AAC support " } ,
{ " mpeg2 " , " USE_MPEG2 " , " libmpeg2 " , false , " MPEG-2 support " } ,
2016-05-11 22:52:14 +06:00
{ " theora " , " USE_THEORADEC " , " libtheora_static " , true , " Theora decoding support " } ,
{ " freetype " , " USE_FREETYPE2 " , " freetype " , true , " FreeType support " } ,
{ " jpeg " , " USE_JPEG " , " jpeg-static " , true , " libjpeg support " } ,
{ " fluidsynth " , " USE_FLUIDSYNTH " , " libfluidsynth " , true , " FluidSynth support " } ,
{ " libcurl " , " USE_LIBCURL " , " libcurl " , true , " libcurl support " } ,
{ " sdlnet " , " USE_SDL_NET " , " SDL_net " , true , " SDL_net support " } ,
2011-04-24 13:33:23 -04:00
// Feature flags
2019-04-22 05:51:09 -07:00
{ " bink " , " USE_BINK " , " " , true , " Bink video support " } ,
{ " scalers " , " USE_SCALERS " , " " , true , " Scalers " } ,
{ " hqscalers " , " USE_HQ_SCALERS " , " " , true , " HQ scalers " } ,
{ " 16bit " , " USE_RGB_COLOR " , " " , true , " 16bit color support " } ,
{ " highres " , " USE_HIGHRES " , " " , true , " high resolution " } ,
{ " mt32emu " , " USE_MT32EMU " , " " , true , " integrated MT-32 emulator " } ,
2019-03-09 02:41:35 +05:30
{ " lua " , " USE_LUA " , " " , true , " lua " } ,
2019-04-22 05:51:09 -07:00
{ " nasm " , " USE_NASM " , " " , true , " IA-32 assembly support " } , // This feature is special in the regard, that it needs additional handling.
{ " opengl " , " USE_OPENGL " , " " , true , " OpenGL support " } ,
{ " opengles " , " USE_GLES " , " " , true , " forced OpenGL ES mode " } ,
{ " taskbar " , " USE_TASKBAR " , " " , true , " Taskbar integration support " } ,
{ " cloud " , " USE_CLOUD " , " " , true , " Cloud integration support " } ,
{ " translation " , " USE_TRANSLATION " , " " , true , " Translation support " } ,
{ " vkeybd " , " ENABLE_VKEYBD " , " " , false , " Virtual keyboard support " } ,
{ " eventrecorder " , " ENABLE_EVENTRECORDER " , " " , false , " Event recorder support " } ,
{ " updates " , " USE_UPDATES " , " " , false , " Updates support " } ,
{ " dialogs " , " USE_SYSDIALOGS " , " " , true , " System dialogs support " } ,
{ " langdetect " , " USE_DETECTLANG " , " " , true , " System language detection support " } , // This feature actually depends on "translation", there
// is just no current way of properly detecting this...
2019-07-27 01:06:35 +02:00
{ " text-console " , " USE_TEXT_CONSOLE_FOR_DEBUGGER " , " " , false , " Text console debugger " } , // This feature is always applied in xcode projects
2019-12-16 01:03:06 +00:00
{ " tts " , " USE_TTS " , " " , true , " Text to speech support " }
2010-11-10 03:56:42 +00:00
} ;
2011-09-06 16:01:10 -04:00
const Tool s_tools [ ] = {
2017-12-25 21:05:04 +01:00
{ " create_cryo " , true } ,
2011-09-06 16:01:10 -04:00
{ " create_drascula " , true } ,
{ " create_hugo " , true } ,
{ " create_kyradat " , true } ,
{ " create_lure " , true } ,
2013-07-07 05:42:45 -04:00
{ " create_neverhood " , true } ,
2011-09-06 16:01:10 -04:00
{ " create_teenagent " , true } ,
2017-12-25 21:05:04 +01:00
{ " create_titanic " , true } ,
2013-07-07 05:42:45 -04:00
{ " create_tony " , true } ,
2011-09-06 16:01:10 -04:00
{ " create_toon " , true } ,
{ " create_translations " , true } ,
{ " qtable " , true }
} ;
2019-04-15 18:59:00 +01:00
const MSVCVersion s_msvc [ ] = {
// Ver Name Solution Project Toolset LLVM
{ 9 , " Visual Studio 2008 " , " 10.00 " , " 2008 " , " 4.0 " , " v90 " , " LLVM-vs2008 " } ,
{ 10 , " Visual Studio 2010 " , " 11.00 " , " 2010 " , " 4.0 " , " v100 " , " LLVM-vs2010 " } ,
{ 11 , " Visual Studio 2012 " , " 11.00 " , " 2012 " , " 4.0 " , " v110 " , " LLVM-vs2012 " } ,
{ 12 , " Visual Studio 2013 " , " 12.00 " , " 2013 " , " 12.0 " , " v120 " , " LLVM-vs2013 " } ,
{ 14 , " Visual Studio 2015 " , " 12.00 " , " 14 " , " 14.0 " , " v140 " , " LLVM-vs2014 " } ,
2019-04-15 18:59:56 +01:00
{ 15 , " Visual Studio 2017 " , " 12.00 " , " 15 " , " 15.0 " , " v141 " , " llvm " } ,
{ 16 , " Visual Studio 2019 " , " 12.00 " , " Version 16 " , " 16.0 " , " v142 " , " llvm " }
2019-04-15 18:59:00 +01:00
} ;
2020-05-08 13:03:57 -07:00
2020-07-13 04:00:35 +01:00
const std : : pair < std : : string , std : : string > s_canonical_lib_name_map [ ] = {
std : : make_pair ( " jpeg-static " , " jpeg " ) ,
std : : make_pair ( " libfaad " , " faad " ) ,
std : : make_pair ( " libFLAC_static " , " FLAC " ) ,
std : : make_pair ( " libfluidsynth " , " fluidsynth " ) ,
std : : make_pair ( " libmad " , " mad " ) ,
std : : make_pair ( " libmpeg2 " , " mpeg2 " ) ,
std : : make_pair ( " libogg_static " , " ogg " ) ,
std : : make_pair ( " libtheora_static " , " theora " ) ,
std : : make_pair ( " libvorbis_static " , " vorbis " ) ,
std : : make_pair ( " libvorbisfile_static " , " vorbisfile " ) ,
std : : make_pair ( " SDL_net " , " SDL2_net " ) , // Only support SDL2
std : : make_pair ( " win_utf8_io_static " , " FLAC " ) // This is some FLAC-specific library not needed with vcpkg, but as there's '.lib' appended to each library, we can't set it to empty, so set it to FLAC again instead
2020-05-08 13:03:57 -07:00
} ;
2020-05-08 13:17:36 -07:00
2020-07-13 04:00:35 +01:00
const char * s_msvc_arch_names [ ] = { " arm64 " , " x86 " , " x64 " } ;
const char * s_msvc_config_names [ ] = { " arm64 " , " Win32 " , " x64 " } ;
2020-07-14 09:34:04 +02:00
// clang-format on
2010-11-10 03:56:42 +00:00
} // End of anonymous namespace
2020-05-08 13:17:36 -07:00
std : : string getMSVCArchName ( MSVC_Architecture arch ) {
2020-07-13 04:00:35 +01:00
return s_msvc_arch_names [ arch ] ;
2020-05-08 13:17:36 -07:00
}
std : : string getMSVCConfigName ( MSVC_Architecture arch ) {
2020-07-13 04:00:35 +01:00
return s_msvc_config_names [ arch ] ;
2020-05-08 13:17:36 -07:00
}
2020-07-13 04:00:35 +01:00
std : : string getCanonicalLibName ( const std : : string & lib ) {
const size_t libCount = sizeof ( s_canonical_lib_name_map ) / sizeof ( s_canonical_lib_name_map [ 0 ] ) ;
for ( size_t i = 0 ; i < libCount ; + + i ) {
if ( s_canonical_lib_name_map [ i ] . first = = lib ) {
return s_canonical_lib_name_map [ i ] . second ;
}
2020-05-08 13:03:57 -07:00
}
return lib ;
}
2010-11-10 03:56:42 +00:00
FeatureList getAllFeatures ( ) {
const size_t featureCount = sizeof ( s_features ) / sizeof ( s_features [ 0 ] ) ;
FeatureList features ;
for ( size_t i = 0 ; i < featureCount ; + + i )
features . push_back ( s_features [ i ] ) ;
return features ;
}
StringList getFeatureDefines ( const FeatureList & features ) {
StringList defines ;
for ( FeatureList : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; + + i ) {
if ( i - > enable & & i - > define & & i - > define [ 0 ] )
defines . push_back ( i - > define ) ;
}
return defines ;
}
2020-05-08 13:10:09 -07:00
StringList getFeatureLibraries ( const Feature & feature ) {
StringList libraries ;
if ( feature . enable & & feature . libraries & & feature . libraries [ 0 ] ) {
StringList fLibraries = tokenize ( feature . libraries ) ;
libraries . splice ( libraries . end ( ) , fLibraries ) ;
}
2020-05-13 22:46:37 +02:00
// The libraries get sorted as they can get used in algorithms where ordering is a
// precondition, e.g. merge()
libraries . sort ( ) ;
2020-05-08 13:10:09 -07:00
return libraries ;
}
2010-11-10 03:56:42 +00:00
StringList getFeatureLibraries ( const FeatureList & features ) {
StringList libraries ;
for ( FeatureList : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; + + i ) {
2020-07-13 12:43:51 +02:00
StringList fl = getFeatureLibraries ( * i ) ;
for ( StringList : : const_iterator flit = fl . begin ( ) ; flit ! = fl . end ( ) ; + + flit ) {
libraries . push_back ( * flit ) ;
}
2010-11-10 03:56:42 +00:00
}
2020-07-13 12:43:51 +02:00
libraries . sort ( ) ;
2010-11-10 03:56:42 +00:00
return libraries ;
}
bool setFeatureBuildState ( const std : : string & name , FeatureList & features , bool enable ) {
FeatureList : : iterator i = std : : find ( features . begin ( ) , features . end ( ) , name ) ;
if ( i ! = features . end ( ) ) {
i - > enable = enable ;
return true ;
} else {
return false ;
}
}
2018-11-03 23:06:10 +00:00
bool getFeatureBuildState ( const std : : string & name , FeatureList & features ) {
FeatureList : : iterator i = std : : find ( features . begin ( ) , features . end ( ) , name ) ;
if ( i ! = features . end ( ) ) {
return i - > enable ;
} else {
return false ;
}
}
2020-05-08 13:10:09 -07:00
BuildSetup removeFeatureFromSetup ( BuildSetup setup , const std : : string & feature ) {
2020-07-13 12:43:51 +02:00
// TODO: use const_iterator in C++11
for ( FeatureList : : iterator i = setup . features . begin ( ) ; i ! = setup . features . end ( ) ; + + i ) {
2020-05-08 13:10:09 -07:00
if ( i - > enable & & feature = = i - > name ) {
2020-05-14 20:49:50 +02:00
StringList feature_libs = getFeatureLibraries ( * i ) ;
for ( StringList : : iterator lib = feature_libs . begin ( ) ; lib ! = feature_libs . end ( ) ; + + lib ) {
2020-05-08 13:10:09 -07:00
if ( setup . useCanonicalLibNames ) {
2020-05-14 20:49:50 +02:00
* lib = getCanonicalLibName ( * lib ) ;
2020-05-08 13:10:09 -07:00
}
2020-05-14 20:49:50 +02:00
setup . libraries . remove ( * lib ) ;
2020-05-08 13:10:09 -07:00
}
if ( i - > define & & i - > define [ 0 ] ) {
setup . defines . remove ( i - > define ) ;
}
setup . features . erase ( i ) ;
break ;
}
}
return setup ;
}
2011-09-06 16:01:10 -04:00
ToolList getAllTools ( ) {
const size_t toolCount = sizeof ( s_tools ) / sizeof ( s_tools [ 0 ] ) ;
ToolList tools ;
for ( size_t i = 0 ; i < toolCount ; + + i )
tools . push_back ( s_tools [ i ] ) ;
return tools ;
}
2019-04-15 18:59:00 +01:00
MSVCList getAllMSVCVersions ( ) {
const size_t msvcCount = sizeof ( s_msvc ) / sizeof ( s_msvc [ 0 ] ) ;
MSVCList msvcVersions ;
for ( size_t i = 0 ; i < msvcCount ; + + i )
msvcVersions . push_back ( s_msvc [ i ] ) ;
return msvcVersions ;
}
const MSVCVersion * getMSVCVersion ( int version ) {
const size_t msvcCount = sizeof ( s_msvc ) / sizeof ( s_msvc [ 0 ] ) ;
for ( size_t i = 0 ; i < msvcCount ; + + i ) {
if ( s_msvc [ i ] . version = = version )
return & s_msvc [ i ] ;
}
return NULL ;
}
2019-04-16 01:09:32 +01:00
int getInstalledMSVC ( ) {
int latest = 0 ;
# if defined(_WIN32) || defined(WIN32)
// Use the Visual Studio Installer to get the latest version
const char * vsWhere = " \" \" %PROGRAMFILES(X86)% \\ Microsoft Visual Studio \\ Installer \\ vswhere.exe \" -latest -legacy -property installationVersion \" " ;
FILE * pipe = _popen ( vsWhere , " rt " ) ;
if ( pipe ! = NULL ) {
char version [ 50 ] ;
if ( fgets ( version , 50 , pipe ) ! = NULL ) {
latest = atoi ( version ) ;
}
_pclose ( pipe ) ;
}
// Use the registry to get the latest version
if ( latest = = 0 ) {
HKEY key ;
LSTATUS err = RegOpenKeyEx ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Microsoft \\ VisualStudio \\ SxS \\ VS7 " , 0 , KEY_QUERY_VALUE | KEY_WOW64_32KEY , & key ) ;
if ( err = = ERROR_SUCCESS & & key ! = NULL ) {
const MSVCList msvc = getAllMSVCVersions ( ) ;
for ( MSVCList : : const_reverse_iterator i = msvc . rbegin ( ) ; i ! = msvc . rend ( ) ; + + i ) {
std : : ostringstream version ;
version < < i - > version < < " .0 " ;
err = RegQueryValueEx ( key , version . str ( ) . c_str ( ) , NULL , NULL , NULL , NULL ) ;
if ( err = = ERROR_SUCCESS ) {
latest = i - > version ;
break ;
}
}
RegCloseKey ( key ) ;
}
}
# endif
return latest ;
}
2010-11-10 03:56:42 +00:00
namespace CreateProjectTool {
//////////////////////////////////////////////////////////////////////////
// Utilities
//////////////////////////////////////////////////////////////////////////
std : : string convertPathToWin ( const std : : string & path ) {
std : : string result = path ;
std : : replace ( result . begin ( ) , result . end ( ) , ' / ' , ' \\ ' ) ;
return result ;
}
std : : string getIndent ( const int indentation ) {
std : : string result ;
for ( int i = 0 ; i < indentation ; + + i )
result + = ' \t ' ;
return result ;
}
void splitFilename ( const std : : string & fileName , std : : string & name , std : : string & ext ) {
const std : : string : : size_type dot = fileName . find_last_of ( ' . ' ) ;
name = ( dot = = std : : string : : npos ) ? fileName : fileName . substr ( 0 , dot ) ;
ext = ( dot = = std : : string : : npos ) ? std : : string ( ) : fileName . substr ( dot + 1 ) ;
}
2015-12-02 14:43:54 +01:00
std : : string basename ( const std : : string & fileName ) {
const std : : string : : size_type slash = fileName . find_last_of ( ' / ' ) ;
2020-07-14 09:34:04 +02:00
if ( slash = = std : : string : : npos )
return fileName ;
2015-12-02 14:43:54 +01:00
return fileName . substr ( slash + 1 ) ;
}
2010-11-10 03:56:42 +00:00
bool producesObjectFile ( const std : : string & fileName ) {
std : : string n , ext ;
splitFilename ( fileName , n , ext ) ;
2015-04-09 19:51:01 +02:00
if ( ext = = " cpp " | | ext = = " c " | | ext = = " asm " | | ext = = " m " | | ext = = " mm " )
2010-11-10 03:56:42 +00:00
return true ;
else
return false ;
}
2013-09-11 20:36:38 -04:00
std : : string toString ( int num ) {
2017-11-11 11:46:47 -06:00
std : : ostringstream os ;
os < < num ;
return os . str ( ) ;
2013-09-11 20:36:38 -04:00
}
2010-11-10 03:56:42 +00:00
/**
* Checks whether the give file in the specified directory is present in the given
* file list .
*
2011-04-27 17:00:38 -04:00
* This function does as special match against the file list . Object files ( . o ) are
* excluded by default and it will not take file extensions into consideration ,
* when the extension of a file in the specified directory is one of " h " , " cpp " ,
* " c " or " asm " .
2010-11-10 03:56:42 +00:00
*
* @ param dir Parent directory of the file .
* @ param fileName File name to match .
* @ param fileList List of files to match against .
* @ return " true " when the file is in the list , " false " otherwise .
*/
bool isInList ( const std : : string & dir , const std : : string & fileName , const StringList & fileList ) {
std : : string compareName , extensionName ;
splitFilename ( fileName , compareName , extensionName ) ;
if ( ! extensionName . empty ( ) )
compareName + = ' . ' ;
for ( StringList : : const_iterator i = fileList . begin ( ) ; i ! = fileList . end ( ) ; + + i ) {
if ( i - > compare ( 0 , dir . size ( ) , dir ) )
continue ;
// When no comparison name is given, we try to match whether a subset of
// the given directory should be included. To do that we must assure that
// the first character after the substring, having the same size as dir, must
// be a path delimiter.
if ( compareName . empty ( ) ) {
if ( i - > size ( ) > = dir . size ( ) + 1 & & i - > at ( dir . size ( ) ) = = ' / ' )
return true ;
else
continue ;
}
2012-07-14 16:33:41 -04:00
const std : : string lastPathComponent = ProjectProvider : : getLastPathComponent ( * i ) ;
2011-04-27 17:00:38 -04:00
if ( extensionName = = " o " ) {
return false ;
} else if ( ! producesObjectFile ( fileName ) & & extensionName ! = " h " ) {
2010-11-10 03:56:42 +00:00
if ( fileName = = lastPathComponent )
return true ;
} else {
if ( ! lastPathComponent . compare ( 0 , compareName . size ( ) , compareName ) )
return true ;
}
}
return false ;
}
/**
* A strict weak compare predicate for sorting a list of
* " FileNode * " entries .
*
* It will sort directory nodes before file nodes .
*
* @ param l Left - hand operand .
* @ param r Right - hand operand .
* @ return " true " if and only if l should be sorted before r .
*/
bool compareNodes ( const FileNode * l , const FileNode * r ) {
if ( ! l ) {
return false ;
} else if ( ! r ) {
return true ;
} else {
if ( l - > children . empty ( ) & & ! r - > children . empty ( ) ) {
return false ;
} else if ( ! l - > children . empty ( ) & & r - > children . empty ( ) ) {
return true ;
} else {
return l - > name < r - > name ;
}
}
}
FileList listDirectory ( const std : : string & dir ) {
FileList result ;
2016-07-07 07:49:18 +02:00
# if defined(_WIN32) || defined(WIN32)
2010-11-10 03:56:42 +00:00
WIN32_FIND_DATA fileInformation ;
HANDLE fileHandle = FindFirstFile ( ( dir + " /* " ) . c_str ( ) , & fileInformation ) ;
if ( fileHandle = = INVALID_HANDLE_VALUE )
return result ;
do {
if ( fileInformation . cFileName [ 0 ] = = ' . ' )
continue ;
result . push_back ( FSNode ( fileInformation . cFileName , ( fileInformation . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ! = 0 ) ) ;
} while ( FindNextFile ( fileHandle , & fileInformation ) = = TRUE ) ;
FindClose ( fileHandle ) ;
# else
DIR * dirp = opendir ( dir . c_str ( ) ) ;
struct dirent * dp = NULL ;
if ( dirp = = NULL )
return result ;
while ( ( dp = readdir ( dirp ) ) ! = NULL ) {
if ( dp - > d_name [ 0 ] = = ' . ' )
continue ;
struct stat st ;
if ( stat ( ( dir + ' / ' + dp - > d_name ) . c_str ( ) , & st ) )
continue ;
result . push_back ( FSNode ( dp - > d_name , S_ISDIR ( st . st_mode ) ) ) ;
}
closedir ( dirp ) ;
# endif
return result ;
}
2013-11-07 12:58:35 +01:00
void createDirectory ( const std : : string & dir ) {
# if defined(_WIN32) || defined(WIN32)
if ( ! CreateDirectory ( dir . c_str ( ) , NULL ) ) {
if ( GetLastError ( ) ! = ERROR_ALREADY_EXISTS ) {
error ( " Could not create folder \" " + dir + " \" " ) ;
}
}
# else
if ( mkdir ( dir . c_str ( ) , 0777 ) = = - 1 ) {
if ( errno = = EEXIST ) {
// Try to open as a folder (might be a file / symbolic link)
DIR * dirp = opendir ( dir . c_str ( ) ) ;
if ( dirp = = NULL ) {
error ( " Could not create folder \" " + dir + " \" " ) ;
} else {
// The folder exists, just close the stream and return
closedir ( dirp ) ;
}
} else {
error ( " Could not create folder \" " + dir + " \" " ) ;
}
}
# endif
}
2010-11-10 03:56:42 +00:00
/**
* Scans the specified directory against files , which should be included
* in the project files . It will not include files present in the exclude list .
*
* @ param dir Directory in which to search for files .
* @ param includeList Files to include in the project .
* @ param excludeList Files to exclude from the project .
* @ return Returns a file node for the specific directory .
*/
FileNode * scanFiles ( const std : : string & dir , const StringList & includeList , const StringList & excludeList ) {
FileList files = listDirectory ( dir ) ;
if ( files . empty ( ) )
return 0 ;
FileNode * result = new FileNode ( dir ) ;
assert ( result ) ;
for ( FileList : : const_iterator i = files . begin ( ) ; i ! = files . end ( ) ; + + i ) {
if ( i - > isDirectory ) {
const std : : string subDirName = dir + ' / ' + i - > name ;
if ( ! isInList ( subDirName , std : : string ( ) , includeList ) )
continue ;
FileNode * subDir = scanFiles ( subDirName , includeList , excludeList ) ;
if ( subDir ) {
subDir - > name = i - > name ;
result - > children . push_back ( subDir ) ;
}
continue ;
}
if ( isInList ( dir , i - > name , excludeList ) )
continue ;
std : : string name , ext ;
splitFilename ( i - > name , name , ext ) ;
if ( ext ! = " h " ) {
if ( ! isInList ( dir , i - > name , includeList ) )
continue ;
}
FileNode * child = new FileNode ( i - > name ) ;
assert ( child ) ;
result - > children . push_back ( child ) ;
}
if ( result - > children . empty ( ) ) {
delete result ;
return 0 ;
} else {
result - > children . sort ( compareNodes ) ;
return result ;
}
}
//////////////////////////////////////////////////////////////////////////
// Project Provider methods
//////////////////////////////////////////////////////////////////////////
ProjectProvider : : ProjectProvider ( StringList & global_warnings , std : : map < std : : string , StringList > & project_warnings , const int version )
2020-07-14 09:34:04 +02:00
: _version ( version ) , _globalWarnings ( global_warnings ) , _projectWarnings ( project_warnings ) {
2010-11-10 03:56:42 +00:00
}
2013-07-07 11:23:19 -04:00
void ProjectProvider : : createProject ( BuildSetup & setup ) {
std : : string targetFolder ;
2011-09-06 16:01:10 -04:00
if ( setup . devTools ) {
_uuidMap = createToolsUUIDMap ( ) ;
2013-07-07 11:23:19 -04:00
targetFolder = " /devtools/ " ;
} else if ( ! setup . tests ) {
_uuidMap = createUUIDMap ( setup ) ;
targetFolder = " /engines/ " ;
}
2010-11-10 03:56:42 +00:00
2013-07-07 11:23:19 -04:00
// We also need to add the UUID of the main project file.
2019-06-16 00:19:38 +01:00
const std : : string svmUUID = _uuidMap [ setup . projectName ] = createUUID ( setup . projectName ) ;
2011-09-06 16:01:10 -04:00
2013-07-07 11:23:19 -04:00
createWorkspace ( setup ) ;
2010-11-10 03:56:42 +00:00
2013-07-07 11:23:19 -04:00
StringList in , ex ;
2011-09-06 16:01:10 -04:00
2013-07-07 11:23:19 -04:00
// Create project files
for ( UUIDMap : : const_iterator i = _uuidMap . begin ( ) ; i ! = _uuidMap . end ( ) ; + + i ) {
if ( i - > first = = setup . projectName )
continue ;
2015-04-04 18:17:10 +02:00
// Retain the files between engines if we're creating a single project
2020-07-14 09:34:04 +02:00
in . clear ( ) ;
ex . clear ( ) ;
2015-04-09 18:30:03 +02:00
2013-07-07 11:23:19 -04:00
const std : : string moduleDir = setup . srcDir + targetFolder + i - > first ;
2011-09-06 16:01:10 -04:00
2013-07-07 11:23:19 -04:00
createModuleList ( moduleDir , setup . defines , setup . testDirs , in , ex ) ;
2015-04-09 18:30:03 +02:00
createProjectFile ( i - > first , i - > second , setup , moduleDir , in , ex ) ;
2013-07-07 11:23:19 -04:00
}
2011-09-06 16:01:10 -04:00
2013-07-07 11:23:19 -04:00
if ( setup . tests ) {
// Create the main project file.
2020-07-14 09:34:04 +02:00
in . clear ( ) ;
ex . clear ( ) ;
2013-07-07 11:23:19 -04:00
createModuleList ( setup . srcDir + " /backends " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /backends/platform/sdl " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /base " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /common " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /engines " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /graphics " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /gui " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /audio " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /test " , setup . defines , setup . testDirs , in , ex ) ;
2011-09-06 16:01:10 -04:00
2013-07-07 11:23:19 -04:00
createProjectFile ( setup . projectName , svmUUID , setup , setup . srcDir , in , ex ) ;
} else if ( ! setup . devTools ) {
2011-09-06 16:01:10 -04:00
// Last but not least create the main project file.
2020-07-14 09:34:04 +02:00
in . clear ( ) ;
ex . clear ( ) ;
2011-09-06 16:01:10 -04:00
// File list for the Project file
2013-07-07 11:23:19 -04:00
createModuleList ( setup . srcDir + " /backends " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /backends/platform/sdl " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /base " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /common " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /engines " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /graphics " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /gui " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /audio " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /audio/softsynth/mt32 " , setup . defines , setup . testDirs , in , ex ) ;
createModuleList ( setup . srcDir + " /video " , setup . defines , setup . testDirs , in , ex ) ;
2014-02-27 21:27:23 -05:00
createModuleList ( setup . srcDir + " /image " , setup . defines , setup . testDirs , in , ex ) ;
2010-11-10 03:56:42 +00:00
2011-09-06 16:01:10 -04:00
// Resource files
2015-12-01 21:00:32 +01:00
addResourceFiles ( setup , in , ex ) ;
2010-11-10 03:56:42 +00:00
2011-09-06 16:01:10 -04:00
// Various text files
in . push_back ( setup . srcDir + " /AUTHORS " ) ;
in . push_back ( setup . srcDir + " /COPYING " ) ;
in . push_back ( setup . srcDir + " /COPYING.LGPL " ) ;
2012-04-17 14:45:22 +02:00
in . push_back ( setup . srcDir + " /COPYING.BSD " ) ;
in . push_back ( setup . srcDir + " /COPYING.FREEFONT " ) ;
2019-04-27 12:22:35 +02:00
in . push_back ( setup . srcDir + " /COPYING.OFL " ) ;
2011-09-06 16:01:10 -04:00
in . push_back ( setup . srcDir + " /COPYRIGHT " ) ;
in . push_back ( setup . srcDir + " /NEWS " ) ;
in . push_back ( setup . srcDir + " /README " ) ;
in . push_back ( setup . srcDir + " /TODO " ) ;
2010-11-10 03:56:42 +00:00
2011-09-06 16:01:10 -04:00
// Create the main project file.
createProjectFile ( setup . projectName , svmUUID , setup , setup . srcDir , in , ex ) ;
}
2013-07-07 11:23:19 -04:00
// Create other misc. build files
createOtherBuildFiles ( setup ) ;
2013-11-07 12:58:34 +01:00
// In case we create the main ScummVM project files we will need to
// generate engines/plugins_table.h too.
if ( ! setup . tests & & ! setup . devTools ) {
createEnginePluginsTable ( setup ) ;
}
2010-11-10 03:56:42 +00:00
}
ProjectProvider : : UUIDMap ProjectProvider : : createUUIDMap ( const BuildSetup & setup ) const {
UUIDMap result ;
for ( EngineDescList : : const_iterator i = setup . engines . begin ( ) ; i ! = setup . engines . end ( ) ; + + i ) {
if ( ! i - > enable | | isSubEngine ( i - > name , setup . engines ) )
continue ;
2019-06-16 00:19:38 +01:00
result [ i - > name ] = createUUID ( i - > name ) ;
2010-11-10 03:56:42 +00:00
}
return result ;
}
2011-09-06 16:01:10 -04:00
ProjectProvider : : UUIDMap ProjectProvider : : createToolsUUIDMap ( ) const {
UUIDMap result ;
ToolList tools = getAllTools ( ) ;
for ( ToolList : : const_iterator i = tools . begin ( ) ; i ! = tools . end ( ) ; + + i ) {
if ( ! i - > enable )
continue ;
2019-06-16 00:19:38 +01:00
result [ i - > name ] = createUUID ( i - > name ) ;
2011-09-06 16:01:10 -04:00
}
return result ;
}
2019-06-16 00:19:38 +01:00
const int kUUIDLen = 16 ;
2010-11-10 03:56:42 +00:00
std : : string ProjectProvider : : createUUID ( ) const {
2011-04-08 16:51:15 +02:00
# ifdef USE_WIN32_API
2010-11-10 03:56:42 +00:00
UUID uuid ;
2019-06-16 00:19:38 +01:00
RPC_STATUS status = UuidCreateSequential ( & uuid ) ;
if ( status ! = RPC_S_OK & & status ! = RPC_S_UUID_LOCAL_ONLY )
error ( " UuidCreateSequential failed " ) ;
2010-11-10 03:56:42 +00:00
unsigned char * string = 0 ;
if ( UuidToStringA ( & uuid , & string ) ! = RPC_S_OK )
error ( " UuidToStringA failed " ) ;
std : : string result = std : : string ( ( char * ) string ) ;
std : : transform ( result . begin ( ) , result . end ( ) , result . begin ( ) , toupper ) ;
RpcStringFreeA ( & string ) ;
return result ;
# else
2019-06-16 00:19:38 +01:00
unsigned char uuid [ kUUIDLen ] ;
2010-11-10 03:56:42 +00:00
2019-06-16 00:19:38 +01:00
for ( int i = 0 ; i < kUUIDLen ; + + i )
2010-11-10 03:56:42 +00:00
uuid [ i ] = ( unsigned char ) ( ( std : : rand ( ) / ( double ) ( RAND_MAX ) ) * 0xFF ) ;
2020-07-14 09:34:04 +02:00
uuid [ 8 ] & = 0xBF ;
uuid [ 8 ] | = 0x80 ;
uuid [ 6 ] & = 0x4F ;
uuid [ 6 ] | = 0x40 ;
2010-11-10 03:56:42 +00:00
2019-06-16 00:19:38 +01:00
return UUIDToString ( uuid ) ;
# endif
}
std : : string ProjectProvider : : createUUID ( const std : : string & name ) const {
# ifdef USE_WIN32_API
HCRYPTPROV hProv = NULL ;
if ( ! CryptAcquireContext ( & hProv , NULL , NULL , PROV_RSA_FULL , CRYPT_VERIFYCONTEXT ) ) {
error ( " CryptAcquireContext failed " ) ;
}
2020-07-14 09:34:04 +02:00
2019-06-16 00:19:38 +01:00
// Use MD5 hashing algorithm
HCRYPTHASH hHash = NULL ;
if ( ! CryptCreateHash ( hProv , CALG_MD5 , 0 , 0 , & hHash ) ) {
CryptReleaseContext ( hProv , 0 ) ;
error ( " CryptCreateHash failed " ) ;
}
// Hash unique ScummVM namespace {5f5b43e8-35ff-4f1e-ad7e-a2a87e9b5254}
const BYTE uuidNs [ kUUIDLen ] =
2020-07-14 09:34:04 +02:00
{ 0x5f , 0x5b , 0x43 , 0xe8 , 0x35 , 0xff , 0x4f , 0x1e , 0xad , 0x7e , 0xa2 , 0xa8 , 0x7e , 0x9b , 0x52 , 0x54 } ;
2019-06-16 00:19:38 +01:00
if ( ! CryptHashData ( hHash , uuidNs , kUUIDLen , 0 ) ) {
CryptDestroyHash ( hHash ) ;
CryptReleaseContext ( hProv , 0 ) ;
error ( " CryptHashData failed " ) ;
}
// Hash project name
if ( ! CryptHashData ( hHash , ( const BYTE * ) name . c_str ( ) , name . length ( ) , 0 ) ) {
CryptDestroyHash ( hHash ) ;
CryptReleaseContext ( hProv , 0 ) ;
error ( " CryptHashData failed " ) ;
}
// Get resulting UUID
BYTE uuid [ kUUIDLen ] ;
DWORD len = kUUIDLen ;
if ( ! CryptGetHashParam ( hHash , HP_HASHVAL , uuid , & len , 0 ) ) {
CryptDestroyHash ( hHash ) ;
CryptReleaseContext ( hProv , 0 ) ;
error ( " CryptGetHashParam failed " ) ;
}
// Add version and variant
2020-07-14 09:34:04 +02:00
uuid [ 6 ] & = 0x0F ;
uuid [ 6 ] | = 0x30 ;
uuid [ 8 ] & = 0x3F ;
uuid [ 8 ] | = 0x80 ;
2019-06-16 00:19:38 +01:00
CryptDestroyHash ( hHash ) ;
CryptReleaseContext ( hProv , 0 ) ;
return UUIDToString ( uuid ) ;
# else
// Fallback to random UUID
return createUUID ( ) ;
# endif
}
std : : string ProjectProvider : : UUIDToString ( unsigned char * uuid ) const {
2010-11-10 03:56:42 +00:00
std : : stringstream uuidString ;
uuidString < < std : : hex < < std : : uppercase < < std : : setfill ( ' 0 ' ) ;
2019-06-16 00:19:38 +01:00
for ( int i = 0 ; i < kUUIDLen ; + + i ) {
2010-11-10 03:56:42 +00:00
uuidString < < std : : setw ( 2 ) < < ( int ) uuid [ i ] ;
if ( i = = 3 | | i = = 5 | | i = = 7 | | i = = 9 ) {
uuidString < < std : : setw ( 0 ) < < ' - ' ;
}
}
return uuidString . str ( ) ;
}
2012-07-14 16:33:41 -04:00
std : : string ProjectProvider : : getLastPathComponent ( const std : : string & path ) {
std : : string : : size_type pos = path . find_last_of ( ' / ' ) ;
if ( pos = = std : : string : : npos )
return path ;
else
return path . substr ( pos + 1 ) ;
}
2010-11-10 03:56:42 +00:00
void ProjectProvider : : addFilesToProject ( const std : : string & dir , std : : ofstream & projectFile ,
const StringList & includeList , const StringList & excludeList ,
const std : : string & filePrefix ) {
// Check for duplicate object file names
StringList duplicate ;
for ( StringList : : const_iterator i = includeList . begin ( ) ; i ! = includeList . end ( ) ; + + i ) {
2016-12-17 15:12:52 -05:00
std : : string fileName = getLastPathComponent ( * i ) ;
std : : transform ( fileName . begin ( ) , fileName . end ( ) , fileName . begin ( ) , tolower ) ;
2010-11-10 03:56:42 +00:00
// Leave out non object file names.
if ( fileName . size ( ) < 2 | | fileName . compare ( fileName . size ( ) - 2 , 2 , " .o " ) )
continue ;
// Check whether an duplicate has been found yet
if ( std : : find ( duplicate . begin ( ) , duplicate . end ( ) , fileName ) ! = duplicate . end ( ) )
continue ;
// Search for duplicates
2020-07-14 09:34:04 +02:00
StringList : : const_iterator j = i ;
+ + j ;
2010-11-10 03:56:42 +00:00
for ( ; j ! = includeList . end ( ) ; + + j ) {
2016-12-17 15:12:52 -05:00
std : : string candidateFileName = getLastPathComponent ( * j ) ;
std : : transform ( candidateFileName . begin ( ) , candidateFileName . end ( ) , candidateFileName . begin ( ) , tolower ) ;
if ( fileName = = candidateFileName ) {
2010-11-10 03:56:42 +00:00
duplicate . push_back ( fileName ) ;
break ;
}
}
}
FileNode * files = scanFiles ( dir , includeList , excludeList ) ;
writeFileListToProject ( * files , projectFile , 0 , duplicate , std : : string ( ) , filePrefix + ' / ' ) ;
delete files ;
}
2013-07-07 11:23:19 -04:00
void ProjectProvider : : createModuleList ( const std : : string & moduleDir , const StringList & defines , StringList & testDirs , StringList & includeList , StringList & excludeList ) const {
2010-11-10 03:56:42 +00:00
const std : : string moduleMkFile = moduleDir + " /module.mk " ;
std : : ifstream moduleMk ( moduleMkFile . c_str ( ) ) ;
if ( ! moduleMk )
error ( moduleMkFile + " is not present " ) ;
includeList . push_back ( moduleMkFile ) ;
std : : stack < bool > shouldInclude ;
shouldInclude . push ( true ) ;
2011-12-28 05:14:59 +02:00
StringList filesInVariableList ;
2010-11-10 03:56:42 +00:00
bool hadModule = false ;
std : : string line ;
for ( ; ; ) {
std : : getline ( moduleMk , line ) ;
if ( moduleMk . eof ( ) )
break ;
if ( moduleMk . fail ( ) )
error ( " Failed while reading from " + moduleMkFile ) ;
TokenList tokens = tokenize ( line ) ;
if ( tokens . empty ( ) )
continue ;
TokenList : : const_iterator i = tokens . begin ( ) ;
if ( * i = = " MODULE " ) {
if ( hadModule )
error ( " More than one MODULE definition in " + moduleMkFile ) ;
// Format: "MODULE := path/to/module"
if ( tokens . size ( ) < 3 )
error ( " Malformed MODULE definition in " + moduleMkFile ) ;
+ + i ;
if ( * i ! = " := " )
error ( " Malformed MODULE definition in " + moduleMkFile ) ;
+ + i ;
std : : string moduleRoot = unifyPath ( * i ) ;
if ( moduleDir . compare ( moduleDir . size ( ) - moduleRoot . size ( ) , moduleRoot . size ( ) , moduleRoot ) )
error ( " MODULE root " + moduleRoot + " does not match base dir " + moduleDir ) ;
hadModule = true ;
} else if ( * i = = " MODULE_OBJS " ) {
if ( tokens . size ( ) < 3 )
error ( " Malformed MODULE_OBJS definition in " + moduleMkFile ) ;
+ + i ;
// This is not exactly correct, for example an ":=" would usually overwrite
// all already added files, but since we do only save the files inside
// includeList or excludeList currently, we couldn't handle such a case easily.
// (includeList and excludeList should always preserve their entries, not added
// by this function, thus we can't just clear them on ":=" or "=").
// But hopefully our module.mk files will never do such things anyway.
if ( * i ! = " := " & & * i ! = " += " & & * i ! = " = " )
error ( " Malformed MODULE_OBJS definition in " + moduleMkFile ) ;
+ + i ;
while ( i ! = tokens . end ( ) ) {
if ( * i = = " \\ " ) {
std : : getline ( moduleMk , line ) ;
tokens = tokenize ( line ) ;
i = tokens . begin ( ) ;
2011-12-28 05:14:59 +02:00
} else if ( * i = = " $(KYRARPG_COMMON_OBJ) " ) {
// HACK to fix EOB/LOL compilation in the kyra engine:
// replace the variable name with the stored files.
// This assumes that the file list has already been defined.
if ( filesInVariableList . size ( ) = = 0 )
error ( " $(KYRARPG_COMMON_OBJ) found, but the variable hasn't been set before it " ) ;
// Construct file list and replace the variable
for ( StringList : : iterator j = filesInVariableList . begin ( ) ; j ! = filesInVariableList . end ( ) ; + + j ) {
const std : : string filename = * j ;
if ( shouldInclude . top ( ) ) {
// In case we should include a file, we need to make
// sure it is not in the exclude list already. If it
// is we just drop it from the exclude list.
excludeList . remove ( filename ) ;
includeList . push_back ( filename ) ;
} else if ( std : : find ( includeList . begin ( ) , includeList . end ( ) , filename ) = = includeList . end ( ) ) {
// We only add the file to the exclude list in case it
// has not yet been added to the include list.
excludeList . push_back ( filename ) ;
}
}
+ + i ;
2010-11-10 03:56:42 +00:00
} else {
2011-05-06 20:41:21 +02:00
const std : : string filename = moduleDir + " / " + unifyPath ( * i ) ;
if ( shouldInclude . top ( ) ) {
// In case we should include a file, we need to make
// sure it is not in the exclude list already. If it
// is we just drop it from the exclude list.
excludeList . remove ( filename ) ;
includeList . push_back ( filename ) ;
} else if ( std : : find ( includeList . begin ( ) , includeList . end ( ) , filename ) = = includeList . end ( ) ) {
// We only add the file to the exclude list in case it
// has not yet been added to the include list.
excludeList . push_back ( filename ) ;
}
2010-11-10 03:56:42 +00:00
+ + i ;
}
}
2011-12-28 05:14:59 +02:00
} else if ( * i = = " KYRARPG_COMMON_OBJ " ) {
// HACK to fix EOB/LOL compilation in the kyra engine: add the
// files defined in the KYRARPG_COMMON_OBJ variable in a list
if ( tokens . size ( ) < 3 )
error ( " Malformed KYRARPG_COMMON_OBJ definition in " + moduleMkFile ) ;
+ + i ;
if ( * i ! = " := " & & * i ! = " += " & & * i ! = " = " )
error ( " Malformed KYRARPG_COMMON_OBJ definition in " + moduleMkFile ) ;
+ + i ;
while ( i ! = tokens . end ( ) ) {
if ( * i = = " \\ " ) {
std : : getline ( moduleMk , line ) ;
tokens = tokenize ( line ) ;
i = tokens . begin ( ) ;
} else {
const std : : string filename = moduleDir + " / " + unifyPath ( * i ) ;
filesInVariableList . push_back ( filename ) ;
+ + i ;
}
}
2013-07-07 11:23:19 -04:00
} else if ( * i = = " TESTS " ) {
if ( tokens . size ( ) < 3 )
error ( " Malformed TESTS definition in " + moduleMkFile ) ;
+ + i ;
if ( * i ! = " := " & & * i ! = " += " & & * i ! = " = " )
error ( " Malformed TESTS definition in " + moduleMkFile ) ;
+ + i ;
while ( i ! = tokens . end ( ) ) {
// Read input
std : : string folder = unifyPath ( * i ) ;
// Get include folder
const std : : string source_dir = " $(srcdir)/ " ;
const std : : string selector = getLastPathComponent ( folder ) ;
const std : : string module = getLastPathComponent ( moduleDir ) ;
folder . replace ( folder . find ( source_dir ) , source_dir . length ( ) , " " ) ;
folder . replace ( folder . find ( selector ) , selector . length ( ) , " " ) ;
folder . replace ( folder . find ( module ) , module . length ( ) , moduleDir ) ;
// Scan all files in the include folder
FileList files = listDirectory ( folder ) ;
if ( files . empty ( ) )
continue ;
// Add to list of test folders
testDirs . push_back ( folder ) ;
for ( FileList : : const_iterator f = files . begin ( ) ; f ! = files . end ( ) ; + + f ) {
if ( f - > isDirectory )
continue ;
std : : string filename = folder + f - > name ;
if ( shouldInclude . top ( ) ) {
// In case we should include a file, we need to make
// sure it is not in the exclude list already. If it
// is we just drop it from the exclude list.
excludeList . remove ( filename ) ;
includeList . push_back ( filename ) ;
} else if ( std : : find ( includeList . begin ( ) , includeList . end ( ) , filename ) = = includeList . end ( ) ) {
// We only add the file to the exclude list in case it
// has not yet been added to the include list.
excludeList . push_back ( filename ) ;
}
}
+ + i ;
}
2010-11-10 03:56:42 +00:00
} else if ( * i = = " ifdef " ) {
if ( tokens . size ( ) < 2 )
error ( " Malformed ifdef in " + moduleMkFile ) ;
+ + i ;
if ( std : : find ( defines . begin ( ) , defines . end ( ) , * i ) = = defines . end ( ) )
shouldInclude . push ( false ) ;
else
2017-06-21 18:40:07 +02:00
shouldInclude . push ( true & & shouldInclude . top ( ) ) ;
2010-11-10 03:56:42 +00:00
} else if ( * i = = " ifndef " ) {
if ( tokens . size ( ) < 2 )
error ( " Malformed ifndef in " + moduleMkFile ) ;
+ + i ;
if ( std : : find ( defines . begin ( ) , defines . end ( ) , * i ) = = defines . end ( ) )
2017-06-21 18:40:07 +02:00
shouldInclude . push ( true & & shouldInclude . top ( ) ) ;
2010-11-10 03:56:42 +00:00
else
shouldInclude . push ( false ) ;
} else if ( * i = = " else " ) {
2017-06-21 18:40:07 +02:00
bool last = shouldInclude . top ( ) ;
shouldInclude . pop ( ) ;
shouldInclude . push ( ! last & & shouldInclude . top ( ) ) ;
2010-11-10 03:56:42 +00:00
} else if ( * i = = " endif " ) {
if ( shouldInclude . size ( ) < = 1 )
error ( " endif without ifdef found in " + moduleMkFile ) ;
shouldInclude . pop ( ) ;
} else if ( * i = = " elif " ) {
error ( " Unsupported operation 'elif' in " + moduleMkFile ) ;
} else if ( * i = = " ifeq " ) {
//XXX
shouldInclude . push ( false ) ;
}
}
if ( shouldInclude . size ( ) ! = 1 )
error ( " Malformed file " + moduleMkFile ) ;
}
2013-11-07 12:58:34 +01:00
void ProjectProvider : : createEnginePluginsTable ( const BuildSetup & setup ) {
2013-11-07 12:58:35 +01:00
// First we need to create the "engines" directory.
createDirectory ( setup . outputDir + " /engines " ) ;
// Then, we can generate the actual "plugins_table.h" file.
2013-11-07 12:58:34 +01:00
const std : : string enginePluginsTableFile = setup . outputDir + " /engines/plugins_table.h " ;
std : : ofstream enginePluginsTable ( enginePluginsTableFile . c_str ( ) ) ;
if ( ! enginePluginsTable ) {
error ( " Could not open \" " + enginePluginsTableFile + " \" for writing " ) ;
}
enginePluginsTable < < " /* This file is automatically generated by create_project */ \n "
< < " /* DO NOT EDIT MANUALLY */ \n "
< < " // This file is being included by \" base/plugins.cpp \" \n " ;
for ( EngineDescList : : const_iterator i = setup . engines . begin ( ) , end = setup . engines . end ( ) ; i ! = end ; + + i ) {
// We ignore all sub engines here because they require no special
// handling.
if ( isSubEngine ( i - > name , setup . engines ) ) {
continue ;
}
// Make the engine name all uppercase.
std : : string engineName ;
std : : transform ( i - > name . begin ( ) , i - > name . end ( ) , std : : back_inserter ( engineName ) , toupper ) ;
enginePluginsTable < < " #if PLUGIN_ENABLED_STATIC( " < < engineName < < " ) \n "
< < " LINK_PLUGIN( " < < engineName < < " ) \n "
< < " #endif \n " ;
}
}
2020-07-14 09:34:04 +02:00
} // namespace CreateProjectTool
2010-11-10 03:56:42 +00:00
void error ( const std : : string & message ) {
std : : cerr < < " ERROR: " < < message < < " ! " < < std : : endl ;
std : : exit ( - 1 ) ;
}