module
build
;
private
import
build_bn
;
version
(
unix
)
version
=
Unix
;
version
(
Unix
)
version
=
Posix
;
version
(
linux
)
version
=
Posix
;
version
(
darwin
)
version
=
Posix
;
version
(
build
)
{
version
(
Windows
)
{
pragma
(
build_def
,
"VERSION 2.9"
)
;
}
}
private
{
import
source
;
import
util
.
str
;
import
util
.
fdt
;
import
util
.
pathex
;
import
util
.
fileex
;
import
util
.
macro
;
import
std
.
c
.
stdio
;
import
std
.
file
;
import
std
.
outbuffer
;
import
std
.
path
;
import
std
.
stdio
;
import
std
.
stream
;
import
std
.
string
;
version
(
Windows
)
{
import
std
.
c
.
windows
.
windows
;
}
else
version
(
linux
)
{
import
std
.
c
.
linux
.
linux
;
}
else
version
(
darwin
)
{
import
std
.
c
.
darwin
.
darwin
;
}
extern
(
C
)
{
char
*
getenv
(
char
*
)
;
int
putenv
(
char
*
)
;
int
system
(
char
*
)
;
}
enum
LibOpt
{
Implicit
,
Build
,
DontBuild
}
const
{
version
(
Windows
)
{
char
[
]
kExeExtention
=
`exe`
;
char
[
]
kLibExtention
=
`lib`
;
char
[
]
kObjExtention
=
`obj`
;
char
[
]
kShrLibExtention
=
`dll`
;
}
version
(
Posix
)
{
char
[
]
kExeExtention
=
``
;
char
[
]
kLibExtention
=
`a`
;
char
[
]
kObjExtention
=
`o`
;
char
[
]
kShrLibExtention
=
`s`
;
}
char
[
]
kSrcExtention
=
`d`
;
char
[
]
kMacroExtention
=
`mac`
;
}
version
(
DigitalMars
)
{
version
(
Windows
)
{
char
[
]
vCompiler
=
`dmd.exe`
;
char
[
]
vCompilerSwitch
=
` -c`
;
char
[
]
vLinker
=
`dmd.exe`
;
char
[
]
vConfigFile
=
`sc.ini`
;
char
[
]
vCompilerPath
=
``
;
char
[
]
vConfigPath
=
``
;
char
[
]
vLibPaths
=
``
;
char
[
]
vConfigSep
=
";"
;
char
[
]
vLibrarian
=
`lib`
;
char
[
]
vLibrarianOpts
=
`-c -p256`
;
}
version
(
Posix
)
{
char
[
]
vCompiler
=
`dmd`
;
char
[
]
vCompilerSwitch
=
` -c`
;
char
[
]
vLinker
=
`dmd`
;
char
[
]
vConfigFile
=
`dmd.conf`
;
char
[
]
vCompilerPath
=
``
;
char
[
]
vConfigPath
=
`/etc/`
;
char
[
]
vLibPaths
=
``
;
char
[
]
vConfigSep
=
":"
;
char
[
]
vLibrarian
=
`ar`
;
char
[
]
vLibrarianOpts
=
`-r`
;
}
char
[
]
vVersionSwitch
=
"-version="
;
char
[
]
vDebugSwitch
=
"-debug"
;
char
[
]
vKeepPathSwitch
=
"-op"
;
char
[
]
vOutFileSwitch
=
"-of"
;
char
[
]
vImportPathSwitch
=
"-I"
;
char
[
]
vNoLinkSwitch
=
"-c"
;
}
version
(
GNU
)
{
version
(
Windows
)
{
char
[
]
vCompiler
=
`gdc.exe`
;
char
[
]
vCompilerSwitch
=
` -c`
;
char
[
]
vLinker
=
`gdc.exe`
;
char
[
]
vConfigFile
=
null
;
char
[
]
vCompilerPath
=
``
;
char
[
]
vConfigPath
=
null
;
char
[
]
vLibPaths
=
``
;
char
[
]
vConfigSep
=
";"
;
char
[
]
vLibrarian
=
`lib`
;
char
[
]
vLibrarianOpts
=
`-c`
;
}
version
(
Posix
)
{
char
[
]
vCompiler
=
`gdc`
;
char
[
]
vCompilerSwitch
=
` -c`
;
char
[
]
vLinker
=
`gdc`
;
char
[
]
vConfigFile
=
null
;
char
[
]
vCompilerPath
=
`/opt/gdc/bin`
;
char
[
]
vConfigPath
=
null
;
char
[
]
vLibPaths
=
``
;
char
[
]
vConfigSep
=
":"
;
char
[
]
vLibrarian
=
`ar`
;
char
[
]
vLibrarianOpts
=
`-r`
;
}
char
[
]
vVersionSwitch
=
"-fversion="
;
char
[
]
vDebugSwitch
=
"-fdebug"
;
char
[
]
vOutFileSwitch
=
"-o "
;
char
[
]
vKeepPathSwitch
=
""
;
char
[
]
vImportPathSwitch
=
"-I "
;
char
[
]
vNoLinkSwitch
=
"-c"
;
}
char
[
]
vBuildImportPathSwitch
=
"-I"
;
char
[
]
vTemporaryPathSwitch
=
"-od"
;
char
[
]
vRunSwitch
=
"-run"
;
char
[
]
vLibrarianPath
=
""
;
char
[
]
*
vDelayedValue
=
null
;
char
[
]
vTemporaryPath
=
""
;
bool
vTestRun
=
false
;
bool
vNoLink
=
false
;
bool
vForceCompile
=
false
;
bool
vSilent
=
false
;
bool
vCleanup
=
false
;
bool
vVerbose
=
false
;
bool
vNames
=
false
;
bool
vAllObjects
=
false
;
bool
vNoDef
=
false
;
bool
vAutoImports
=
true
;
bool
vMacroInput
=
true
;
bool
vExecuteProgram
=
false
;
char
[
]
vRunParms
;
char
[
]
vTargetExe
;
char
[
]
[
]
vImportRoots
;
char
[
]
[
]
vModulesToIgnore
;
char
[
]
[
]
vModulesToNotice
;
char
[
]
[
]
vBuildDef
;
char
[
]
[
]
vDefaultLibs
;
char
[
]
[
]
vDefaultCompArgs
;
LibOpt
vLibraryAction
=
LibOpt
.
Implicit
;
char
[
]
vAppPath
;
char
[
]
vAppName
;
char
[
]
vAppVersion
=
"2.9"
;
char
[
]
vTargetName
;
char
[
]
vPragmaTargetName
;
char
[
]
vCommandTargetName
;
char
[
]
[
]
vCmdLineSourceFiles
;
bool
[
char
[
]
]
vLinkFiles
;
char
[
]
[
]
vCombinedArgs
;
char
[
]
[
]
vBuildArgs
;
char
[
]
[
]
vCompilerArgs
;
bool
vUseResponseFile
;
bool
vConsoleApp
=
true
;
char
[
]
vRDFName
=
"default.rdf"
;
bool
[
char
[
]
]
vNestedDelim
;
struct
ExternRef
{
char
[
]
FilePath
;
char
[
]
[
]
ToolOpts
;
}
ExternRef
[
]
vExternals
;
Substitute
[
]
vSubstitutions
;
version
(
Windows
)
{
char
[
]
vWinVer
=
""
;
ubyte
vWinVerNum
;
}
}
static
this
(
)
{
source
.
ActivateVersion
(
"build"
)
;
vDefaultCompArgs
~=
vKeepPathSwitch
;
vModulesToIgnore
~=
"phobos"
;
version
(
Posix
)
{
vDefaultCompArgs
~=
vVersionSwitch
~
"Posix"
;
}
version
(
Windows
)
{
vWinVerNum
=
cast
(
ubyte
)
(
GetVersion
(
)
&
0xFF
)
;
vWinVer
=
std
.
string
.
format
(
"%d.0"
,
vWinVerNum
)
;
}
version
(
DigitalMars
)
{
version
(
Windows
)
{
vUseResponseFile
=
true
;
}
else
{
vUseResponseFile
=
false
;
}
}
else
{
vUseResponseFile
=
false
;
}
vNestedDelim
[
"("
]
=
true
;
vNestedDelim
[
"<"
]
=
true
;
vNestedDelim
[
"{"
]
=
true
;
vNestedDelim
[
"["
]
=
true
;
}
void
DisplayUsage
(
bool
pFull
=
true
)
{
writefln
(
"Path and Version : %s v%s(%d)\n  built on %s"
,
vAppPath
,
vAppVersion
,
build_bn
.
auto_build_number
,
__TIMESTAMP__
)
;
if
(
pFull
==
false
)
return
;
else
{
writefln
(
"Usage: %s sourcefile [options objectfiles libraries]"
,
vAppName
)
;
writefln
(
"  sourcefile D source file"
)
;
writefln
(
"  -v         Verbose (passed through to D)"
)
;
writefln
(
"  -V         Verbose (NOT passed through)"
)
;
writefln
(
"  -names     Displays the names of the files used in building the target."
)
;
writefln
(
"  -DCPATH<path> <path> is where the compiler has been installed."
)
;
writefln
(
"             Only needed if the compiler is not in the system's"
)
;
writefln
(
"             PATH list. Used if you are testing an alternate"
)
;
writefln
(
"             version of the compiler."
)
;
writefln
(
"  -CFPATH<path> <path> is where the D config file has been installed."
)
;
writefln
(
"  -full      Causes all source files, except ignored modules,"
)
;
writefln
(
"              to be compiled."
)
;
writefln
(
"  -link      Forces the linker to be called instead of the librarian."
)
;
writefln
(
"              (Only needed if the source files do not contain"
)
;
writefln
(
"               main/WinMain)"
)
;
writefln
(
"  -nolink    Ensures that the linker is not called."
)
;
writefln
(
"              (Only needed if main/WinMain is found in the source"
)
;
writefln
(
"               files and you do NOT want an executable created.)"
)
;
writefln
(
"  -lib       Forces the object files to be placed in a library."
)
;
writefln
(
"              (Only needed if main/WinMain is found in the source"
)
;
writefln
(
"               files AND you want it in a library instead of"
)
;
writefln
(
"               an executable.)"
)
;
writefln
(
"  -nolib     Ensures that the object files are not used to form"
)
;
writefln
(
"              a library."
)
;
writefln
(
"              (Only needed if main/WinMain is not found in the source"
)
;
writefln
(
"               files and you do NOT want a library."
)
;
writefln
(
"  -obj       This is the same as having both -nolib and -nolink switches."
)
;
writefln
(
"  -allobj    Ensures that all object files are added to a"
)
;
writefln
(
"              library."
)
;
writefln
(
"              (Normally only those in the same directory are added.)"
)
;
writefln
(
"  -cleanup   Ensures that all object files created during the run"
)
;
writefln
(
"              are removed at the end of the run, plus other work files."
)
;
writefln
(
"  -clean     Same as -cleanup"
)
;
version
(
Windows
)
{
writefln
(
"  -gui[:x.y] Forces a GUI application to be created. The optional"
)
;
writefln
(
"              :x.y can be used to build an application for a "
)
;
writefln
(
"              specific version of Windows. eg. -gui:4.0"
)
;
writefln
(
"              (Only needed if WinMain is not found in the source files"
)
;
writefln
(
"               or if you wish to override the default Windows version)"
)
;
writefln
(
"  -dll       Forces a DLL library to be created."
)
;
writefln
(
"              (Only needed if DllMain is not found in the source files.)"
)
;
}
writefln
(
"  -LIBOPT<opt> Allows you to pass <opt> to the librarian."
)
;
writefln
(
"  -LIBPATH=<pathlist> Used to add a semi-colon delimited list"
)
;
writefln
(
"                of search paths for library files."
)
;
writefln
(
"  -test      Does everything as normal except it displays the commands"
)
;
writefln
(
"              instead of running them."
)
;
writefln
(
"  -RDF<path> Overrides the default Rule Definition File"
)
;
writefln
(
"  -R<y|n>    Indicates whether to use a response file or command line"
)
;
writefln
(
"              arguments with the compiler tools."
)
;
writefln
(
"               -Ry will cause a response to be used."
)
;
writefln
(
"               -Rn will cause command line arguments to be used."
)
;
writefln
(
"               -R will reverse the current usage."
)
;
version
(
DigitalMars
)
{
version
(
Windows
)
{
writefln
(
"               ** The default is to use a response file"
)
;
}
else
{
writefln
(
"               ** The default is to use command line arguments"
)
;
}
}
else
{
writefln
(
"               ** The default is to use command line arguments"
)
;
}
writefln
(
"  -run<param> If the link is successful, this will cause the"
)
;
writefln
(
"               executable just created to run. You can give it "
)
;
writefln
(
"               run time parameters. Anything after the '-run' will"
)
;
writefln
(
"               placed in the program's command line. You will need"
)
;
writefln
(
"               to quote any embedded spaces."
)
;
writefln
(
"  -od<path>  Nominate the directory where temporary (work) files"
)
;
writefln
(
"             are to be created. By default they are created in"
)
;
writefln
(
"             the same directory as the target file."
)
;
writefln
(
"  -X<module> Modules/Packages to ignore (eg. -Xmylib)"
)
;
writefln
(
"  -M<module> Modules/Packages to notice (eg. -Mphobos)"
)
;
writefln
(
"  -T<targetname> The name of the target file to create. Normally"
)
;
writefln
(
"              the target name istaken from the first or only name"
)
;
writefln
(
"              of the command line."
)
;
writefln
(
"  -help     Displays the full 'usage' help text. "
)
;
writefln
(
"  -h        Same as -help, displays the full 'usage' help text."
)
;
writefln
(
"  -?        Same as -help, displays the full 'usage' help text."
)
;
writefln
(
"  -silent   Avoids unnecessary messages being displayed."
)
;
writefln
(
"  -noautoimport Turns off the automatic addition of source paths"
)
;
writefln
(
"              to the list of Import Roots."
)
;
writefln
(
"  -info      Displays the version and path of the Build application."
)
;
writefln
(
"  -nodef    Prevents a Module Definition File from being created."
)
;
writefln
(
"  [...]      All other options, objectfiles and libraries are"
)
;
writefln
(
"              passed to the compiler"
)
;
writefln
(
"*Note, you can specify all or any command line value in a "
)
;
writefln
(
"   response file. Each value appears in its own line in the"
)
;
writefln
(
"   response file and you reference this file by prefixing"
)
;
writefln
(
"   its name with an '@' symbol on the command line."
)
;
writefln
(
"   Example:  build @final"
)
;
writefln
(
"      where a file called 'final.brf' contains the command"
)
;
writefln
(
"      line values (including other response file references)"
)
;
writefln
(
"   If the response file reference is just a single '@' then"
)
;
writefln
(
"   build looks for a file called 'build.brf'"
)
;
}
}
int
RunCommand
(
char
[
]
pCommand
)
{
int
lRC
;
int
lTrueRC
;
if
(
vTestRun
)
{
writefln
(
"Command: '%s'"
,
pCommand
)
;
return
0
;
}
else
{
if
(
vVerbose
)
{
writefln
(
"Running '%s'"
,
pCommand
)
;
}
lRC
=
system
(
std
.
string
.
toStringz
(
pCommand
)
)
;
version
(
Posix
)
lTrueRC
=
(
(
lRC
&
0xFF00
)
>>
8
)
;
version
(
Windows
)
lTrueRC
=
lRC
;
if
(
vVerbose
)
{
if
(
lTrueRC
==
0
)
{
writefln
(
"Successful"
)
;
}
else
{
writefln
(
"Failed. Return code: %04x"
,
lRC
)
;
}
}
return
lTrueRC
;
}
}
char
[
]
GetEnv
(
char
[
]
pSymbol
)
{
return
std
.
string
.
toString
(
getenv
(
pSymbol
)
)
;
}
FileDateTime
GetNewestDateTime
(
)
{
Source
lSource
;
FileDateTime
lModsTime
=
new
FileDateTime
(
)
;
foreach
(
int
i
,
char
[
]
lFileName
;
Source
.
SourceIndex
.
keys
)
{
lSource
=
Source
.
SourceIndex
[
lFileName
]
;
if
(
lSource
.
Ignore
)
continue
;
lSource
.
search
(
)
;
if
(
vVerbose
)
{
writefln
(
"source file[%d] %s"
,
i
,
util
.
pathex
.
AbbreviateFileName
(
lFileName
)
)
;
}
else
if
(
vNames
)
{
writefln
(
" [ %s ]"
,
util
.
pathex
.
AbbreviateFileName
(
lFileName
)
)
;
}
if
(
lSource
.
DependantsTime
>
lModsTime
)
{
if
(
vVerbose
)
{
writefln
(
"Newer time: from %s to %s"
,
lModsTime
.
toString
(
)
,
lSource
.
DependantsTime
.
toString
(
)
)
;
}
lModsTime
=
lSource
.
DependantsTime
;
}
}
foreach
(
int
i
,
char
[
]
lFileName
;
vLinkFiles
.
keys
)
{
FileDateTime
lLinkTime
=
GetFileTime
(
lFileName
)
;
if
(
vVerbose
)
{
writefln
(
"link file[%d] %s %s"
,
i
,
util
.
pathex
.
AbbreviateFileName
(
lFileName
)
,
lLinkTime
.
toString
(
)
)
;
}
else
if
(
vNames
)
{
writefln
(
" [ %s ]"
,
util
.
pathex
.
AbbreviateFileName
(
lFileName
)
)
;
}
if
(
lLinkTime
>
lModsTime
)
{
if
(
vVerbose
)
{
writefln
(
"Newer time: from %s to %s"
,
lModsTime
.
toString
(
)
,
lLinkTime
.
toString
(
)
)
;
}
lModsTime
=
lLinkTime
;
}
}
return
lModsTime
;
}
struct
Rule
{
char
[
]
Name
;
char
[
]
Input
;
char
[
]
Output
;
char
[
]
Tool
;
}
;
Rule
[
]
LoadRules
(
)
{
Rule
[
]
lRules
;
char
[
]
[
]
lRuleText
;
char
[
]
lRuleDefnFile
;
lRuleDefnFile
=
util
.
pathex
.
LocateFile
(
vRDFName
,
getDirName
(
vAppPath
)
~
std
.
path
.
pathsep
~
GetEnv
(
"PATH"
)
)
;
if
(
vVerbose
)
writefln
(
"Rule Definitions from %s"
,
lRuleDefnFile
)
;
lRuleText
=
GetTextLines
(
lRuleDefnFile
)
;
foreach
(
char
[
]
lLine
;
lRuleText
)
{
lLine
=
std
.
string
.
strip
(
lLine
)
;
if
(
util
.
str
.
begins
(
lLine
,
"rule="
)
>
0
)
{
lRules
.
length
=
lRules
.
length
+
1
;
lRules
[
$
-
1
]
.
Name
=
lLine
[
5
..
$
]
;
}
else
if
(
lRules
.
length
>
0
)
{
if
(
util
.
str
.
begins
(
lLine
,
"in="
)
>
0
)
lRules
[
$
-
1
]
.
Input
=
lLine
[
3
..
$
]
;
else
if
(
util
.
str
.
begins
(
lLine
,
"out="
)
>
0
)
lRules
[
$
-
1
]
.
Output
=
lLine
[
4
..
$
]
;
else
if
(
util
.
str
.
begins
(
lLine
,
"tool="
)
>
0
)
lRules
[
$
-
1
]
.
Tool
=
lLine
[
5
..
$
]
;
}
}
if
(
vVerbose
)
{
foreach
(
Rule
r
;
lRules
)
{
writefln
(
"Rule '%s' ==> in:%s, out:%s, tool:'%s'"
,
r
.
Name
,
r
.
Input
,
r
.
Output
,
r
.
Tool
)
;
}
}
return
lRules
;
}
int
ProcessExternal
(
ExternRef
pRef
)
{
int
lResult
=
-
1
;
static
Rule
[
]
lRules
;
char
[
]
lExtension
;
char
[
]
lInFile
;
char
[
]
lOutFile
;
FileDateTime
lInDate
;
FileDateTime
lOutDate
;
char
[
]
lCommand
;
if
(
lRules
.
length
==
0
)
lRules
=
LoadRules
(
)
;
lExtension
=
std
.
path
.
getExt
(
pRef
.
FilePath
)
;
foreach
(
Rule
r
;
lRules
)
{
lInFile
=
""
;
if
(
lExtension
==
r
.
Input
)
{
lInFile
=
pRef
.
FilePath
;
lOutFile
=
std
.
path
.
addExt
(
pRef
.
FilePath
,
r
.
Output
)
;
}
else
if
(
lExtension
==
r
.
Output
)
{
lOutFile
=
pRef
.
FilePath
;
lInFile
=
std
.
path
.
addExt
(
pRef
.
FilePath
,
r
.
Input
)
;
}
if
(
lInFile
.
length
==
0
)
continue
;
lInFile
=
util
.
pathex
.
LocateFile
(
lInFile
,
vImportRoots
)
;
if
(
!
util
.
fileex
.
FileExists
(
lInFile
)
)
throw
new
Exception
(
std
.
string
.
format
(
"External file '%s' not found"
,
lInFile
)
)
;
lOutFile
=
getDirName
(
lInFile
)
~
std
.
path
.
sep
~
getBaseName
(
lInFile
)
;
lOutFile
=
std
.
path
.
addExt
(
lOutFile
,
r
.
Output
)
;
lInFile
=
util
.
pathex
.
AbbreviateFileName
(
lInFile
)
;
lOutFile
=
util
.
pathex
.
AbbreviateFileName
(
lOutFile
)
;
lInDate
=
new
FileDateTime
(
lInFile
)
;
lOutDate
=
new
FileDateTime
(
lOutFile
)
;
if
(
(
lInDate
>
lOutDate
)
||
vForceCompile
)
{
char
[
]
lKeyValues
;
lKeyValues
=
"@IN="
~
lInFile
~
","
~
"@OUT="
~
lOutFile
;
foreach
(
char
[
]
lOpt
;
pRef
.
ToolOpts
)
{
if
(
std
.
string
.
find
(
lOpt
,
"="
)
!=
-
1
)
lKeyValues
~=
","
~
lOpt
;
}
lCommand
=
util
.
str
.
Expand
(
r
.
Tool
,
lKeyValues
)
;
lResult
=
RunCommand
(
lCommand
)
;
if
(
lResult
!=
0
)
return
lResult
;
}
AddLink
(
lOutFile
)
;
}
return
0
;
}
int
Build
(
)
{
bool
lBuildRequired
;
char
[
]
[
]
lFilesToLink
;
char
[
]
[
]
lFilesToCompile
;
int
lRunResult
;
char
[
]
lTargetName
;
char
[
]
lTargetDir
;
FileDateTime
lTargetTime
;
FileDateTime
lMostRecentTime
;
bool
lCompiling
;
bool
lLinking
;
Source
[
]
lNonLinkingSources
;
char
[
]
lDResponseFileName
;
char
[
]
lLinkResponseFileName
;
char
[
]
lLResponseFileName
;
char
[
]
lDefName
;
char
[
]
lOutText
;
char
[
]
lSourcesToCompile
;
char
[
]
lCommand
;
foreach
(
char
[
]
lFile
;
vCmdLineSourceFiles
)
{
new
Source
(
GetFullPathname
(
lFile
)
)
;
}
lLinking
=
(
vLibraryAction
==
LibOpt
.
Build
)
||
(
Source
.
WasMainFound
==
false
)
||
(
vNoLink
==
true
)
?
false
:
true
;
lMostRecentTime
=
GetNewestDateTime
(
)
;
if
(
vLibraryAction
==
LibOpt
.
Implicit
)
{
if
(
Source
.
WasMainFound
)
{
vLibraryAction
=
LibOpt
.
DontBuild
;
}
else
{
vLibraryAction
=
LibOpt
.
Build
;
}
}
if
(
vPragmaTargetName
.
length
!=
0
)
vTargetName
=
vPragmaTargetName
;
if
(
vCommandTargetName
.
length
!=
0
)
{
char
[
]
lBaseName
;
lBaseName
=
vTargetName
.
dup
;
for
(
int
i
=
lBaseName
.
length
-
1
;
i
>=
0
;
i
--
)
{
if
(
lBaseName
[
i
]
==
'.'
)
{
lBaseName
.
length
=
i
;
break
;
}
}
vTargetName
=
Expand
(
vCommandTargetName
,
"Target="
~
lBaseName
)
;
}
util
.
pathex
.
MakePath
(
vTargetName
)
;
if
(
vLibraryAction
==
LibOpt
.
Build
)
lTargetName
=
ReplaceExtention
(
vTargetName
,
kLibExtention
)
;
else
if
(
vNoLink
==
false
)
if
(
Source
.
WasMainFound
)
if
(
Source
.
WasMainDLL
)
lTargetName
=
ReplaceExtention
(
vTargetName
,
kShrLibExtention
)
;
else
{
lTargetName
=
ReplaceExtention
(
vTargetName
,
kExeExtention
)
;
vTargetExe
=
lTargetName
;
}
else
lTargetName
=
"not defined"
;
else
lTargetName
=
""
;
lTargetName
=
util
.
pathex
.
CanonicalPath
(
lTargetName
,
false
)
;
lTargetName
=
util
.
pathex
.
AbbreviateFileName
(
lTargetName
)
;
if
(
vVerbose
||
vNames
)
{
writefln
(
"\nBuilding target '%s'"
,
lTargetName
)
;
}
if
(
lTargetName
.
length
>
0
)
{
lTargetName
=
util
.
pathex
.
CanonicalPath
(
lTargetName
,
false
)
;
lTargetDir
=
getDirName
(
lTargetName
)
;
lTargetTime
=
util
.
fdt
.
GetFileTime
(
lTargetName
)
;
if
(
vVerbose
)
{
writefln
(
"Time %s for %s (target)"
,
lTargetTime
.
toString
(
)
,
lTargetName
)
;
writefln
(
"Time %s (most recent)"
,
lMostRecentTime
.
toString
(
)
)
;
}
if
(
lTargetTime
<
lMostRecentTime
)
{
lBuildRequired
=
true
;
}
}
foreach
(
ExternRef
lRef
;
vExternals
)
{
lRunResult
=
ProcessExternal
(
lRef
)
;
if
(
lRunResult
!=
0
)
return
lRunResult
;
}
if
(
Source
.
SourceIndex
.
length
==
0
)
{
foreach
(
char
[
]
lFileName
;
vLinkFiles
.
keys
)
{
if
(
util
.
str
.
ends
(
lFileName
,
kObjExtention
)
>=
0
)
lFilesToLink
~=
lFileName
;
}
}
else
foreach
(
int
i
,
char
[
]
lFileName
;
Source
.
SourceIndex
.
keys
)
{
Source
lCurrentSource
;
bool
lNeedsCompiling
;
char
[
]
lShortFileName
;
lNeedsCompiling
=
vForceCompile
;
lCurrentSource
=
Source
.
SourceIndex
[
lFileName
]
;
if
(
lCurrentSource
.
Ignore
)
continue
;
lShortFileName
=
util
.
pathex
.
AbbreviateFileName
(
lFileName
)
;
if
(
std
.
path
.
getExt
(
lShortFileName
)
!=
kSrcExtention
)
continue
;
if
(
lCurrentSource
.
NoLink
)
lNonLinkingSources
~=
lCurrentSource
;
if
(
lCurrentSource
.
FilesTime
>
lCurrentSource
.
ObjectsTime
)
{
if
(
vVerbose
)
writefln
(
"%s newer than its object file"
,
lShortFileName
)
;
lNeedsCompiling
=
true
;
}
else
if
(
lCurrentSource
.
DependantsTime
>
lCurrentSource
.
ObjectsTime
)
{
if
(
vVerbose
)
writefln
(
"%s has newer dependants than its object file."
,
lShortFileName
)
;
lNeedsCompiling
=
true
;
}
if
(
lNeedsCompiling
)
{
lBuildRequired
=
true
;
lCompiling
=
true
;
lFilesToCompile
~=
lShortFileName
;
if
(
lCurrentSource
.
NoLink
==
false
)
lFilesToLink
~=
util
.
pathex
.
AbbreviateFileName
(
lCurrentSource
.
ObjectName
)
;
if
(
!
vTestRun
)
{
if
(
lCurrentSource
.
IncrementBuildNumber
(
)
)
{
if
(
vVerbose
)
writefln
(
"New build number %d for %s"
,
lCurrentSource
.
BuildNumber
,
lCurrentSource
.
ModuleName
)
;
}
}
}
else
if
(
lCurrentSource
.
NoLink
==
false
)
{
lFilesToLink
~=
util
.
pathex
.
AbbreviateFileName
(
lCurrentSource
.
ObjectName
)
;
}
}
if
(
lBuildRequired
==
false
)
{
if
(
vSilent
==
false
)
writefln
(
"Files are up to date, no build required."
)
;
return
0
;
}
lOutText
~=
GatherCompilerArgs
(
lLinking
)
;
foreach
(
char
[
]
lFileName
;
lFilesToCompile
)
{
lSourcesToCompile
~=
util
.
str
.
enquote
(
lFileName
)
~
"\n"
;
}
version
(
Windows
)
{
if
(
Source
.
WasMainGUI
)
{
AddBuildDef
(
"EXETYPE NT"
)
;
if
(
vWinVer
.
length
!=
0
)
AddBuildDef
(
"SUBSYSTEM WINDOWS,"
~
vWinVer
)
;
else
AddBuildDef
(
"SUBSYSTEM WINDOWS"
)
;
vDefaultLibs
~=
"gdi32.lib"
;
}
else
if
(
Source
.
WasMainDLL
)
{
AddBuildDef
(
`LIBRARY "`
~
std
.
path
.
getBaseName
(
lTargetName
)
~
`"`
)
;
AddBuildDef
(
"EXETYPE NT"
)
;
if
(
vWinVer
.
length
!=
0
)
AddBuildDef
(
"SUBSYSTEM WINDOWS,"
~
vWinVer
)
;
else
AddBuildDef
(
"SUBSYSTEM WINDOWS"
)
;
AddBuildDef
(
"CODE PRELOAD DISCARDABLE SHARED EXECUTE"
)
;
AddBuildDef
(
"DATA PRELOAD SINGLE WRITE"
)
;
}
else
if
(
vConsoleApp
)
{
AddBuildDef
(
`EXETYPE DOS`
)
;
}
if
(
(
vNoDef
==
false
)
&&
(
vBuildDef
.
length
>
0
)
)
{
lDefName
=
ReplaceExtention
(
lTargetName
,
"def"
)
;
if
(
vTemporaryPath
.
length
!=
0
)
{
lDefName
=
vTemporaryPath
~
std
.
path
.
getBaseName
(
lDefName
)
;
}
lDefName
=
util
.
pathex
.
AbbreviateFileName
(
lDefName
)
;
util
.
fileex
.
CreateTextFile
(
lDefName
,
vBuildDef
)
;
lOutText
~=
util
.
str
.
enquote
(
lDefName
)
~
"\n"
;
}
}
if
(
lLinking
)
{
foreach
(
char
[
]
lFileName
;
vLinkFiles
.
keys
)
{
char
[
]
lCmdItem
;
version
(
Posix
)
char
[
]
lPrefix
;
if
(
lFileName
.
length
>
0
)
{
lCmdItem
=
lFileName
;
version
(
Posix
)
{
int
lCut
;
if
(
(
lCut
=
util
.
str
.
ends
(
lCmdItem
,
"."
~
kLibExtention
)
)
>=
0
)
{
lCmdItem
=
lCmdItem
[
0
..
lCut
]
;
lPrefix
=
"-L-l"
;
}
}
lCmdItem
=
util
.
str
.
enquote
(
lCmdItem
)
~
"\n"
;
version
(
Posix
)
lOutText
~=
lPrefix
~
lCmdItem
;
version
(
Windows
)
lOutText
~=
lCmdItem
;
}
}
}
if
(
lLinking
||
lCompiling
)
{
if
(
lSourcesToCompile
.
length
>
0
)
{
char
[
]
lCommandLine
;
lCommandLine
=
lOutText
~
lSourcesToCompile
;
if
(
vUseResponseFile
)
{
lDResponseFileName
=
ReplaceExtention
(
lTargetName
,
"rsp"
)
;
if
(
vTemporaryPath
.
length
!=
0
)
{
lDResponseFileName
=
vTemporaryPath
~
std
.
path
.
getBaseName
(
lDResponseFileName
)
;
}
lDResponseFileName
=
util
.
pathex
.
AbbreviateFileName
(
lDResponseFileName
)
;
util
.
fileex
.
CreateTextFile
(
lDResponseFileName
,
lCommandLine
)
;
lCommand
=
vCompilerPath
~
vCompiler
~
vCompilerSwitch
~
" @"
~
lDResponseFileName
;
}
else
{
lCommandLine
=
std
.
string
.
replace
(
lCommandLine
,
"\n"
,
" "
)
;
lCommand
=
vCompilerPath
~
vCompiler
~
vCompilerSwitch
~
" "
~
lCommandLine
;
}
if
(
vVerbose
)
{
writefln
(
"Compiling with ..........\n%s\n"
,
lCommandLine
)
;
}
lRunResult
=
RunCommand
(
lCommand
)
;
if
(
lRunResult
!=
0
)
vExecuteProgram
=
false
;
}
if
(
(
lRunResult
==
0
)
&&
(
lFilesToLink
.
length
>
0
)
&&
(
lLinking
==
true
)
)
{
char
[
]
lCommandLine
;
char
[
]
lSmallName
;
lSmallName
=
util
.
pathex
.
AbbreviateFileName
(
lTargetName
)
;
if
(
find
(
lSmallName
,
" "
)
!=
-
1
)
{
version
(
Posix
)
{
lOutText
~=
std
.
string
.
format
(
`%s"%s"`
,
vOutFileSwitch
,
lSmallName
)
;
}
else
{
lOutText
~=
std
.
string
.
format
(
`"%s%s"`
,
vOutFileSwitch
,
lSmallName
)
;
}
}
else
lOutText
~=
std
.
string
.
format
(
`%s%s`
,
vOutFileSwitch
,
lSmallName
)
;
lOutText
~=
"\n"
;
foreach
(
char
[
]
lLib
;
vDefaultLibs
)
{
lLib
=
util
.
str
.
enquote
(
lLib
)
~
"\n"
;
version
(
Windows
)
lOutText
~=
lLib
;
version
(
Posix
)
lOutText
~=
"-L-l"
~
lLib
;
}
if
(
vLibPaths
.
length
>
1
)
{
vLibPaths
=
vLibPaths
[
1
..
$
]
;
version
(
Windows
)
{
if
(
vVerbose
)
writefln
(
"Setting LIB=%s"
,
vLibPaths
)
;
putenv
(
"LIB="
~
vLibPaths
[
1
..
$
]
)
;
}
version
(
Posix
)
{
if
(
vVerbose
)
writefln
(
"Setting LIB=%s"
,
vLibPaths
)
;
char
[
]
[
]
lLibPaths
;
lLibPaths
=
std
.
string
.
split
(
vLibPaths
,
vConfigSep
)
;
foreach
(
char
[
]
lLib
;
lLibPaths
)
{
if
(
lLib
.
length
>
0
)
lOutText
~=
"-L-L"
~
lLib
~
"\n"
;
}
}
}
lCommandLine
=
lOutText
;
foreach
(
char
[
]
lFile
;
lFilesToLink
)
lCommandLine
~=
lFile
~
"\n"
;
if
(
vUseResponseFile
)
{
lLinkResponseFileName
=
ReplaceExtention
(
lTargetName
,
"ksp"
)
;
if
(
vTemporaryPath
.
length
!=
0
)
{
lLinkResponseFileName
=
vTemporaryPath
~
std
.
path
.
getBaseName
(
lLinkResponseFileName
)
;
}
lLinkResponseFileName
=
util
.
pathex
.
AbbreviateFileName
(
lLinkResponseFileName
)
;
util
.
fileex
.
CreateTextFile
(
lLinkResponseFileName
,
lCommandLine
)
;
lCommand
=
vCompilerPath
~
vLinker
~
" @"
~
lLinkResponseFileName
;
}
else
{
lCommandLine
=
std
.
string
.
replace
(
lCommandLine
,
"\n"
,
" "
)
;
lCommand
=
vCompilerPath
~
vLinker
~
" "
~
lCommandLine
;
}
if
(
vVerbose
)
{
writefln
(
"Linking with ..........\n%s\n"
,
lCommandLine
)
;
}
if
(
vSilent
)
{
version
(
Posix
)
lCommand
~=
" >/dev/null"
;
version
(
Windows
)
lCommand
~=
" >nul"
;
}
lRunResult
=
RunCommand
(
lCommand
)
;
if
(
lRunResult
!=
0
)
vExecuteProgram
=
false
;
}
}
else
{
if
(
vSilent
==
false
)
writefln
(
"No build required."
)
;
lRunResult
=
0
;
}
if
(
(
Source
.
WasMainDLL
)
&&
(
lRunResult
==
0
)
)
{
char
[
]
lTargetFileName
;
char
[
]
lImpLibPath
;
ulong
[
]
lImpManf
;
vExecuteProgram
=
false
;
lImpLibPath
=
util
.
pathex
.
LocateFile
(
"implib.exe"
,
GetEnv
(
"PATH"
)
)
;
if
(
util
.
fileex
.
FileExists
(
lImpLibPath
)
)
{
lImpManf
=
util
.
fileex
.
FindInFile
(
lImpLibPath
,
"Borland"
)
;
if
(
lImpManf
.
length
!=
0
)
lImpLibPath
~=
" -a "
;
else
lImpLibPath
~=
" /system "
;
lTargetFileName
=
std
.
path
.
getBaseName
(
lTargetName
)
;
lRunResult
=
RunCommand
(
lImpLibPath
~
std
.
path
.
addExt
(
lTargetFileName
,
"lib"
)
~
" "
~
std
.
path
.
addExt
(
lTargetFileName
,
"dll"
)
)
;
}
}
else
if
(
(
vLibraryAction
==
LibOpt
.
Build
)
&&
(
lRunResult
==
0
)
)
{
vExecuteProgram
=
false
;
lOutText
.
length
=
0
;
lOutText
~=
vLibrarianOpts
~
std
.
path
.
linesep
;
lOutText
~=
lTargetName
~
std
.
path
.
linesep
;
foreach
(
char
[
]
lFileName
;
lFilesToLink
)
{
char
[
]
lFileDir
;
lFileDir
=
getDirName
(
lFileName
)
;
if
(
vAllObjects
||
lFileDir
==
""
||
lFileDir
==
lTargetDir
)
{
if
(
lFileName
.
length
>
1
+
kSrcExtention
.
length
)
{
if
(
lFileName
[
$
-
kSrcExtention
.
length
..
$
]
==
kSrcExtention
)
{
lFileName
=
lFileName
[
0
..
$
-
kSrcExtention
.
length
]
~
kObjExtention
;
}
}
lOutText
~=
lFileName
~
std
.
path
.
linesep
;
}
}
if
(
vUseResponseFile
)
{
lLResponseFileName
=
ReplaceExtention
(
lTargetName
,
"lsp"
)
;
if
(
vTemporaryPath
.
length
!=
0
)
{
lLResponseFileName
=
vTemporaryPath
~
std
.
path
.
getBaseName
(
lLResponseFileName
)
;
}
util
.
fileex
.
CreateTextFile
(
lLResponseFileName
,
lOutText
)
;
lCommand
=
vLibrarianPath
~
vLibrarian
~
" @"
~
lLResponseFileName
;
}
else
{
lCommand
=
vLibrarianPath
~
vLibrarian
~
" "
~
std
.
string
.
replace
(
lOutText
,
std
.
path
.
linesep
,
" "
)
;
}
if
(
vVerbose
)
{
writefln
(
"Librarian with ..........\n%s\n"
,
lOutText
)
;
}
lRunResult
=
RunCommand
(
lCommand
)
;
}
if
(
vCleanup
)
{
char
[
]
[
]
lHitList
;
if
(
vVerbose
)
{
writefln
(
"Cleaning up ..."
)
;
}
foreach
(
char
[
]
lFileName
;
Source
.
SourceIndex
.
keys
)
{
Source
lSource
;
lSource
=
Source
.
SourceIndex
[
lFileName
]
;
if
(
lSource
.
Ignore
)
continue
;
if
(
lSource
.
ObjectName
.
length
>
0
)
{
lHitList
~=
lSource
.
ObjectName
;
}
}
lHitList
~=
lDResponseFileName
;
lHitList
~=
lLinkResponseFileName
;
lHitList
~=
lLResponseFileName
;
lHitList
~=
lDefName
;
lHitList
~=
ReplaceExtention
(
lTargetName
,
"map"
)
;
lHitList
~=
ReplaceExtention
(
lTargetName
,
"bak"
)
;
lHitList
~=
ReplaceExtention
(
lTargetName
,
"lst"
)
;
foreach
(
char
[
]
lFilename
;
lHitList
)
{
if
(
lFilename
.
length
>
0
)
{
if
(
util
.
fileex
.
FileExists
(
lFilename
)
)
{
if
(
vVerbose
)
{
writefln
(
"  removing %s"
,
lFilename
)
;
}
std
.
file
.
remove
(
lFilename
)
;
}
}
}
}
return
lRunResult
;
}
char
[
]
GatherCompilerArgs
(
bool
pLinking
)
{
char
[
]
lOutText
;
foreach
(
char
[
]
lRoot
;
vImportRoots
)
{
version
(
Posix
)
vDefaultCompArgs
~=
vImportPathSwitch
~
"\""
~
lRoot
~
"\""
;
else
vDefaultCompArgs
~=
vImportPathSwitch
~
lRoot
;
}
foreach
(
char
[
]
lArg
;
vDefaultCompArgs
)
{
AddCompilerArg
(
lArg
)
;
}
foreach
(
char
[
]
lCompileArg
;
vCompilerArgs
)
{
if
(
lCompileArg
.
length
>
0
)
{
if
(
find
(
lCompileArg
,
"\""
)
==
-
1
)
if
(
find
(
lCompileArg
,
" "
)
!=
-
1
)
{
if
(
lCompileArg
[
$
-
1
]
==
'\\'
)
lCompileArg
.
length
=
lCompileArg
.
length
-
1
;
lOutText
~=
std
.
string
.
format
(
`"%s"`
,
lCompileArg
)
;
}
else
lOutText
~=
lCompileArg
;
else
lOutText
~=
lCompileArg
;
lOutText
~=
"\n"
;
}
}
if
(
pLinking
==
false
)
{
if
(
vNoLinkSwitch
.
length
>
0
)
{
if
(
find
(
vNoLinkSwitch
,
" "
)
!=
-
1
)
lOutText
~=
std
.
string
.
format
(
`"%s"`
,
vNoLinkSwitch
)
;
else
lOutText
~=
vNoLinkSwitch
;
lOutText
~=
"\n"
;
AddCompilerArg
(
vNoLinkSwitch
)
;
}
}
return
lOutText
;
}
char
[
]
[
]
ModulesToIgnore
(
)
{
return
vModulesToIgnore
;
}
void
AddExternal
(
char
[
]
pPath
,
char
[
]
[
]
pOpts
)
{
if
(
pPath
.
length
>
0
)
{
vExternals
.
length
=
vExternals
.
length
+
1
;
vExternals
[
$
-
1
]
.
FilePath
=
pPath
;
vExternals
[
$
-
1
]
.
ToolOpts
=
pOpts
;
if
(
vVerbose
)
{
writef
(
"Added external file to be built: %s"
,
pPath
)
;
foreach
(
char
[
]
lOpt
;
pOpts
)
writef
(
" `%s`"
,
lOpt
)
;
writefln
(
""
)
;
}
}
}
void
AddLink
(
char
[
]
pPath
)
{
if
(
pPath
.
length
==
0
)
return
;
if
(
(
pPath
in
vLinkFiles
)
is
null
)
vLinkFiles
[
pPath
]
=
true
;
}
void
AddTarget
(
char
[
]
pPath
)
{
if
(
pPath
.
length
==
0
)
return
;
if
(
vPragmaTargetName
.
length
==
0
)
vPragmaTargetName
=
pPath
;
else
if
(
vPragmaTargetName
!=
pPath
)
{
if
(
vVerbose
)
{
writefln
(
"Multiple pragma(target,...) detected. '%s' will be used and '%s' rejected."
,
vPragmaTargetName
,
pPath
)
;
}
}
}
void
AddBuildDef
(
char
[
]
pText
,
bool
pReplace
=
false
)
{
int
lPos
;
char
[
]
lLowerText
;
static
uint
[
char
[
]
]
lElementIdx
;
if
(
vNoDef
==
true
)
return
;
lLowerText
=
std
.
string
.
tolower
(
pText
)
;
lPos
=
std
.
string
.
find
(
lLowerText
,
' '
)
;
if
(
lPos
==
-
1
)
lPos
=
lLowerText
.
length
;
lLowerText
.
length
=
lPos
;
if
(
lLowerText
in
lElementIdx
)
{
if
(
pReplace
)
vBuildDef
[
lElementIdx
[
lLowerText
]
]
=
pText
;
}
else
{
vBuildDef
~=
pText
;
lElementIdx
[
lLowerText
]
=
vBuildDef
.
length
-
1
;
}
}
void
AddCompilerArg
(
char
[
]
pArg
)
{
bool
lFound
;
if
(
pArg
.
length
>
0
)
{
if
(
pArg
.
length
>
3
)
{
if
(
pArg
[
0
..
3
]
==
`+v+`
)
pArg
=
vVersionSwitch
~
pArg
[
3
..
$
]
;
}
lFound
=
false
;
foreach
(
char
[
]
lArg
;
vCompilerArgs
)
{
if
(
lArg
==
pArg
)
{
lFound
=
true
;
break
;
}
}
if
(
!
lFound
)
vCompilerArgs
~=
pArg
;
}
}
char
[
]
AddRoot
(
char
[
]
pRootName
)
{
static
bool
[
char
[
]
]
lRootHash
;
char
[
]
lFullName
;
char
[
]
lSearchName
;
if
(
pRootName
.
length
==
0
)
{
return
pRootName
;
}
else
{
lFullName
=
util
.
pathex
.
CanonicalPath
(
pRootName
)
;
version
(
Windows
)
lSearchName
=
std
.
string
.
tolower
(
lFullName
)
;
version
(
Posix
)
lSearchName
=
lFullName
;
if
(
!
(
lSearchName
in
lRootHash
)
)
{
vImportRoots
~=
lFullName
;
lRootHash
[
lSearchName
]
=
true
;
return
lFullName
;
}
else
return
""
;
}
}
bool
AutoImports
(
)
{
return
vAutoImports
;
}
char
[
]
[
]
GetImportRoots
(
)
{
return
vImportRoots
;
}
char
[
]
ExpandEnvVar
(
char
[
]
pLine
)
{
char
[
]
lLine
;
char
[
]
lSymName
;
int
lPos
;
int
lEnd
;
lLine
.
length
=
0
;
for
(
lPos
=
0
;
lPos
<
pLine
.
length
;
lPos
++
)
{
if
(
pLine
[
lPos
]
==
'%'
)
{
lSymName
.
length
=
0
;
for
(
lEnd
=
lPos
+
1
;
(
lEnd
<
pLine
.
length
)
&&
(
pLine
[
lEnd
]
!=
'%'
)
;
lEnd
++
)
{
lSymName
~=
pLine
[
lEnd
]
;
}
if
(
lSymName
.
length
>
0
)
{
if
(
lSymName
==
"@P"
)
{
lSymName
=
(
vConfigPath
?
vConfigPath
[
0
..
length
-
1
]
:
""
)
;
}
else
if
(
lSymName
==
"@D"
)
{
lSymName
=
(
vCompilerPath
?
vCompilerPath
[
0
..
length
-
1
]
:
""
)
;
}
else
{
lSymName
=
GetEnv
(
lSymName
)
;
}
lLine
~=
lSymName
;
}
lPos
=
lEnd
;
}
else
{
lLine
~=
pLine
[
lPos
]
;
}
}
return
lLine
;
}
void
Process_DFLAGS
(
char
[
]
pText
)
{
int
lPos
;
int
lEndPos
;
char
[
]
lRootName
;
char
[
]
[
]
lRoots
;
char
[
]
[
]
lArgs
;
int
lArg
;
bool
lInArg
;
char
lQuote
;
lInArg
=
false
;
lArg
=
-
1
;
lQuote
=
0
;
foreach
(
char
lArgChar
;
pText
)
{
if
(
(
lArgChar
==
'"'
)
||
(
lArgChar
==
'\''
)
)
{
if
(
lQuote
==
lArgChar
)
{
lQuote
=
0
;
continue
;
}
if
(
lQuote
==
0
)
{
lQuote
=
lArgChar
;
continue
;
}
}
if
(
lArgChar
==
' '
)
{
if
(
lQuote
==
0
)
{
lInArg
=
false
;
continue
;
}
}
if
(
lInArg
==
false
)
{
lArg
++
;
lArgs
.
length
=
lArg
+
1
;
lInArg
=
true
;
}
lArgs
[
lArg
]
~=
lArgChar
;
}
foreach
(
char
[
]
lSwitch
;
lArgs
)
{
if
(
(
lSwitch
.
length
>
0
)
&&
(
lSwitch
[
0
]
==
'-'
)
)
{
if
(
vDelayedValue
!=
null
)
{
*
vDelayedValue
=
lSwitch
;
vDelayedValue
=
null
;
vBuildArgs
~=
lSwitch
;
continue
;
}
if
(
lSwitch
[
1
]
==
'I'
)
{
lRoots
=
std
.
string
.
split
(
lSwitch
[
2
..
length
]
,
vConfigSep
)
;
foreach
(
char
[
]
lRoot
;
lRoots
)
{
lRootName
=
AddRoot
(
lRoot
)
;
if
(
vVerbose
)
{
if
(
lRootName
.
length
>
0
)
{
writefln
(
" added root from config file %s"
,
lRootName
)
;
}
}
}
}
else
{
version
(
DigitalMars
)
{
if
(
util
.
str
.
IsLike
(
lSwitch
,
(
vOutFileSwitch
~
"*"
)
)
)
{
vCommandTargetName
=
lSwitch
[
vOutFileSwitch
.
length
..
$
]
;
vBuildArgs
~=
lSwitch
;
continue
;
}
}
version
(
GNU
)
{
if
(
lSwitch
==
vOutFileSwitch
)
{
vDelayedValue
=
&
vCommandTargetName
;
vBuildArgs
~=
lSwitch
;
continue
;
}
}
if
(
util
.
str
.
IsLike
(
lSwitch
,
std
.
utf
.
toUTF32
(
vTemporaryPathSwitch
~
"*"
)
)
)
{
char
[
]
lbRoot
;
vTemporaryPath
=
lSwitch
[
vTemporaryPathSwitch
.
length
..
$
]
;
if
(
vTemporaryPath
.
length
>
0
&&
vTemporaryPath
[
$
-
1
..
$
]
!=
std
.
path
.
sep
)
vTemporaryPath
~=
std
.
path
.
sep
;
version
(
DigitalMars
)
{
lbRoot
=
AddRoot
(
vTemporaryPath
)
;
if
(
lbRoot
.
length
>
0
)
{
if
(
vVerbose
)
{
writefln
(
"Added root from config file Object Write Path = %s"
,
lbRoot
)
;
}
util
.
pathex
.
MakePath
(
lbRoot
)
;
}
}
vBuildArgs
~=
lSwitch
;
}
AddCompilerArg
(
lSwitch
)
;
}
}
}
}
void
ReadEnviron
(
)
{
char
[
]
lSymValue
;
lSymValue
=
GetEnv
(
"DFLAGS"
)
;
if
(
lSymValue
.
length
>
0
)
{
if
(
vVerbose
)
writefln
(
"Analyzing environment symbol DFLAGS=%s"
,
lSymValue
)
;
Process_DFLAGS
(
lSymValue
)
;
}
}
void
ReadConfigFile
(
)
{
char
[
]
lPath
;
char
[
]
[
]
lTextLines
;
int
lPos
;
if
(
vConfigFile
is
null
)
{
return
;
}
lPath
=
vConfigPath
~
vConfigFile
;
lTextLines
=
util
.
fileex
.
GetTextLines
(
lPath
,
util
.
fileex
.
GetOpt
.
Exists
)
;
if
(
vVerbose
)
{
writefln
(
"Reading from config: %s"
,
lPath
)
;
}
foreach
(
int
i
,
char
[
]
lLine
;
lTextLines
)
{
while
(
lLine
.
length
>
0
&&
lLine
[
lLine
.
length
-
1
]
<=
' '
)
{
lLine
.
length
=
lLine
.
length
-
1
;
}
if
(
vVerbose
)
{
writefln
(
" Line %d: %s"
,
i
+
1
,
lLine
)
;
}
lLine
=
ExpandEnvVar
(
lLine
)
;
lPos
=
find
(
lLine
,
"DFLAGS="
)
;
if
(
lPos
==
0
)
{
Process_DFLAGS
(
lLine
[
lPos
+
7
..
length
]
)
;
}
lPos
=
find
(
lLine
,
"LIB="
)
;
if
(
lPos
==
0
)
{
char
[
]
[
]
lPaths
;
lLine
=
lLine
[
lPos
+
4
..
length
]
;
lPaths
.
length
=
1
;
foreach
(
char
lChar
;
lLine
)
{
if
(
lChar
==
'"'
)
{
}
else
if
(
lChar
==
';'
)
{
lPaths
.
length
=
lPaths
.
length
+
1
;
}
else
lPaths
[
$
-
1
]
~=
lChar
;
}
for
(
int
i
=
0
;
i
<
lPaths
.
length
;
i
++
)
{
lPaths
[
i
]
=
std
.
string
.
strip
(
lPaths
[
i
]
)
;
}
foreach
(
char
[
]
lPath
;
lPaths
)
{
if
(
lPath
.
length
>
0
)
{
if
(
lPath
[
0
]
==
'"'
&&
lPath
[
length
-
1
]
==
'"'
)
{
lPath
=
lPath
[
1
..
length
-
1
]
;
}
vLibPaths
~=
vConfigSep
;
vLibPaths
~=
(
"\""
~
util
.
pathex
.
CanonicalPath
(
lPath
)
~
"\""
)
;
}
}
if
(
vVerbose
)
{
writefln
(
" use %s"
,
vLibPaths
)
;
}
continue
;
}
lPos
=
find
(
lLine
,
"LINKCMD="
)
;
if
(
lPos
==
0
)
{
while
(
(
lPos
=
find
(
lLine
,
"\""
)
)
!=
-
1
)
{
lLine
=
lLine
[
0
..
lPos
]
~
lLine
[
lPos
+
1
..
$
]
;
}
if
(
vLibrarianPath
.
length
==
0
)
{
vLibrarianPath
=
std
.
path
.
getDirName
(
lLine
[
8
..
$
]
)
~
std
.
path
.
sep
;
vLibrarianPath
=
util
.
pathex
.
CanonicalPath
(
vLibrarianPath
)
;
if
(
vVerbose
)
{
writefln
(
" librarian path %s"
,
vLibrarianPath
)
;
}
}
continue
;
}
lPos
=
find
(
lLine
,
"LIBCMD="
)
;
if
(
lPos
==
0
)
{
while
(
(
lPos
=
find
(
lLine
,
"\""
)
)
!=
-
1
)
{
lLine
=
lLine
[
0
..
lPos
]
~
lLine
[
lPos
+
1
..
$
]
;
}
vLibrarianPath
=
std
.
path
.
getDirName
(
lLine
[
7
..
$
]
)
~
std
.
path
.
sep
;
vLibrarianPath
=
util
.
pathex
.
CanonicalPath
(
vLibrarianPath
)
;
vLibrarian
=
std
.
path
.
getBaseName
(
lLine
[
7
..
$
]
)
;
if
(
vVerbose
)
{
writefln
(
" librarian path %s"
,
vLibrarianPath
)
;
writefln
(
" librarian is %s"
,
vLibrarian
)
;
}
}
}
}
void
DisplayItems
(
char
[
]
[
]
pList
,
char
[
]
pTitle
=
""
)
{
if
(
pList
.
length
>
0
)
{
if
(
pTitle
.
length
>
0
)
writefln
(
"\n%s"
,
pTitle
)
;
foreach
(
int
lIndex
,
char
[
]
lListEntry
;
pList
)
{
writefln
(
" [%2d]: %s"
,
lIndex
,
lListEntry
)
;
}
}
}
void
DisplayItems
(
ExternRef
[
]
pList
,
char
[
]
pTitle
=
""
)
{
if
(
pList
.
length
>
0
)
{
if
(
pTitle
.
length
>
0
)
writefln
(
"\n%s"
,
pTitle
)
;
foreach
(
int
lIndex
,
ExternRef
lListEntry
;
pList
)
{
writef
(
" [%2d]: %s"
,
lIndex
,
lListEntry
.
FilePath
)
;
if
(
lListEntry
.
ToolOpts
.
length
>
0
)
foreach
(
char
[
]
lOpt
;
lListEntry
.
ToolOpts
)
writef
(
" [%s]"
,
lOpt
)
;
writefln
(
""
)
;
}
}
}
char
[
]
GetTemporaryPath
(
)
{
return
vTemporaryPath
;
}
Substitute
[
]
GetMacros
(
)
{
return
vSubstitutions
;
}
char
[
]
GetFullPathname
(
char
[
]
pFileName
)
{
char
[
]
lPossiblePath
;
char
[
]
lLocalPath
;
lLocalPath
=
util
.
pathex
.
CanonicalPath
(
pFileName
,
false
)
;
if
(
util
.
fileex
.
FileExists
(
lLocalPath
)
)
{
return
util
.
pathex
.
AbbreviateFileName
(
lLocalPath
)
;
}
foreach
(
char
[
]
lNextRoot
;
vImportRoots
)
{
lPossiblePath
=
(
lNextRoot
~
pFileName
)
;
if
(
util
.
fileex
.
FileExists
(
lPossiblePath
)
)
{
return
util
.
pathex
.
AbbreviateFileName
(
lPossiblePath
)
;
}
}
return
util
.
pathex
.
AbbreviateFileName
(
lLocalPath
)
;
}
char
[
]
FindFileInPathList
(
char
[
]
pSymName
,
char
[
]
pFileName
)
{
char
[
]
[
]
lPaths
;
char
[
]
lCompilerPath
;
char
[
]
lRawValue
;
lRawValue
=
GetEnv
(
pSymName
)
;
if
(
lRawValue
.
length
==
0
)
lRawValue
=
pSymName
;
lPaths
=
split
(
util
.
str
.
toASCII
(
lRawValue
)
,
std
.
path
.
pathsep
)
;
lCompilerPath
.
length
=
0
;
foreach
(
char
[
]
lPath
;
lPaths
)
{
if
(
lPath
.
length
>
0
)
{
if
(
lPath
[
length
-
1
]
!=
std
.
path
.
sep
[
0
]
)
lPath
~=
std
.
path
.
sep
;
if
(
util
.
fileex
.
FileExists
(
lPath
~
pFileName
)
)
{
lCompilerPath
=
lPath
;
break
;
}
}
}
return
lCompilerPath
;
}
int
main
(
char
[
]
[
]
pArgs
)
{
int
lBuildResult
;
char
[
]
lCompPath
;
bool
lSetPath
=
false
;
source
.
AddRoot
=
&
AddRoot
;
source
.
GetImportRoots
=
&
GetImportRoots
;
source
.
ModulesToIgnore
=
&
ModulesToIgnore
;
source
.
AutoImports
=
&
AutoImports
;
source
.
AddTarget
=
&
AddTarget
;
source
.
AddLink
=
&
AddLink
;
source
.
AddExternal
=
&
AddExternal
;
source
.
AddBuildDef
=
&
AddBuildDef
;
source
.
GetFullPathname
=
&
GetFullPathname
;
source
.
GetObjWritePath
=
&
GetTemporaryPath
;
source
.
GetMacros
=
&
GetMacros
;
source
.
AddCompilerArg
=
&
AddCompilerArg
;
lCompPath
=
FindFileInPathList
(
"PATH"
,
vCompiler
)
;
if
(
lCompPath
.
length
>
0
)
{
if
(
lCompPath
[
length
-
1
]
!=
std
.
path
.
sep
[
0
]
)
lCompPath
~=
std
.
path
.
sep
;
vCompilerPath
=
lCompPath
.
dup
;
if
(
!
(
vConfigPath
is
null
)
&&
(
vConfigPath
.
length
==
0
)
)
vConfigPath
=
lCompPath
.
dup
;
}
if
(
vCompilerPath
.
length
==
0
)
{
vCompilerPath
=
util
.
pathex
.
GetInitCurDir
;
lSetPath
=
true
;
}
vAppPath
=
pArgs
[
0
]
;
vAppName
=
getBaseName
(
vAppPath
)
;
version
(
Windows
)
{
int
DotPos
;
DotPos
=
rfind
(
vAppName
,
'.'
)
;
if
(
DotPos
!=
-
1
)
{
vAppName
.
length
=
DotPos
;
}
}
pArgs
=
pArgs
[
1
..
pArgs
.
length
]
;
if
(
pArgs
.
length
==
0
)
{
DisplayUsage
(
)
;
return
0
;
}
GatherArgs
(
pArgs
)
;
source
.
mVerboseMode
=
vVerbose
;
if
(
vVerbose
)
{
writefln
(
"*** build v%s (build %d)***"
,
vAppVersion
,
build_bn
.
auto_build_number
)
;
}
foreach
(
char
[
]
lArg
;
vCombinedArgs
)
{
ProcessCmdLineArg
(
lArg
)
;
}
source
.
mMacroInput
=
vMacroInput
;
if
(
vMacroInput
)
ProcessMacroDefs
(
vVerbose
)
;
if
(
(
vTargetName
.
length
==
0
)
&&
(
vCommandTargetName
.
length
==
0
)
)
{
throw
new
Exception
(
"No target name supplied."
)
;
}
if
(
vVerbose
||
vNames
)
writefln
(
"Current Dir '%s'"
,
util
.
pathex
.
GetInitCurDir
(
)
)
;
if
(
lSetPath
)
{
if
(
vVerbose
)
{
writefln
(
"%s not found in PATH symbol, so assuming current directory"
,
vCompiler
)
;
}
}
if
(
vCompilerPath
[
length
-
1
]
!=
std
.
path
.
sep
[
0
]
)
vCompilerPath
~=
std
.
path
.
sep
;
if
(
vConfigPath
.
length
==
0
)
{
vConfigPath
=
vCompilerPath
;
if
(
vVerbose
)
{
writefln
(
"No configuration file path, so assuming current directory"
)
;
}
}
if
(
vConfigPath
[
length
-
1
]
!=
std
.
path
.
sep
[
0
]
)
vConfigPath
~=
std
.
path
.
sep
;
version
(
DigitalMars
)
{
if
(
util
.
fileex
.
FileExists
(
vConfigPath
~
vConfigFile
)
==
false
)
{
throw
new
Exception
(
std
.
string
.
format
(
"The configuration file '%s' was not found."
,
vConfigPath
~
vConfigFile
)
)
;
}
}
if
(
util
.
fileex
.
FileExists
(
vCompilerPath
~
vCompiler
)
==
false
)
{
throw
new
Exception
(
std
.
string
.
format
(
"The compiler '%s' was not found."
,
vCompilerPath
~
vCompiler
)
)
;
}
if
(
vVerbose
)
{
writefln
(
"Compiler installed in %s"
,
vCompilerPath
)
;
writefln
(
"Configuration File installed in %s"
,
vConfigPath
)
;
}
source
.
SetKnownVersions
(
)
;
ReadEnviron
(
)
;
version
(
DigitalMars
)
ReadConfigFile
(
)
;
foreach
(
char
[
]
m
;
vModulesToNotice
)
{
for
(
int
i
=
0
;
i
<
vModulesToIgnore
.
length
;
i
++
)
{
if
(
vModulesToIgnore
[
i
]
==
m
)
{
vModulesToIgnore
=
vModulesToIgnore
[
0
..
i
]
~
vModulesToIgnore
[
i
+
1
..
length
]
;
i
--
;
}
}
}
bool
lAllExist
=
true
;
foreach
(
char
[
]
lFile
;
vCmdLineSourceFiles
)
{
if
(
!
util
.
fileex
.
FileExists
(
lFile
)
)
{
if
(
vSilent
==
false
)
writefln
(
"** File '%s' not found."
,
lFile
)
;
lAllExist
=
false
;
}
}
if
(
lAllExist
==
false
)
{
throw
new
Exception
(
"Not all supplied files exist."
)
;
}
lBuildResult
=
Build
(
)
;
if
(
vVerbose
)
{
writefln
(
""
)
;
DisplayItems
(
vBuildArgs
,
"build args: ..............."
)
;
DisplayItems
(
vCompilerArgs
,
"compiler args: ................"
)
;
DisplayItems
(
vCmdLineSourceFiles
,
"command line files: ..............."
)
;
DisplayItems
(
Source
.
SourceIndex
.
keys
,
"source files: ..............."
)
;
DisplayItems
(
vLinkFiles
.
keys
,
"link files: ..............."
)
;
DisplayItems
(
vExternals
,
"externally built files: ..............."
)
;
DisplayItems
(
vImportRoots
,
"import roots: ................."
)
;
DisplayItems
(
vModulesToIgnore
,
"ignored packages: ................."
)
;
DisplayItems
(
vModulesToNotice
,
"noticed package: ................."
)
;
}
if
(
vExecuteProgram
&&
(
vTargetExe
.
length
>
0
)
)
{
RunCommand
(
vTargetExe
~
" "
~
std
.
string
.
strip
(
vRunParms
)
)
;
}
return
lBuildResult
;
}
void
ProcessResponseFile
(
char
[
]
pArg
,
bool
pVerbose
)
{
char
[
]
lRespFileName
;
char
[
]
[
]
lRespLines
;
if
(
pArg
.
length
==
1
)
lRespFileName
=
"@build.brf"
;
else
lRespFileName
=
pArg
[
1
..
length
]
.
dup
;
if
(
std
.
path
.
getExt
(
lRespFileName
)
.
length
==
0
)
{
lRespFileName
~=
".brf"
;
}
if
(
pVerbose
)
writefln
(
"Response file %s"
,
lRespFileName
)
;
lRespLines
=
util
.
fileex
.
GetTextLines
(
lRespFileName
,
util
.
fileex
.
GetOpt
.
Exists
)
;
foreach
(
char
[
]
lArg
;
lRespLines
)
{
int
lPos
=
std
.
string
.
find
(
lArg
,
"#"
)
;
if
(
lPos
!=
-
1
)
{
lArg
.
length
=
lPos
;
}
lArg
=
std
.
string
.
strip
(
lArg
)
;
if
(
lArg
.
length
>
1
)
{
if
(
pVerbose
)
writefln
(
"Response file arg: %s"
,
lArg
)
;
GatherOneArg
(
lArg
)
;
}
}
}
void
ProcessCmdLineArg
(
char
[
]
pArg
)
{
char
[
]
lNewPath
;
static
char
[
]
lImportSwitch
;
int
lCut
;
if
(
util
.
str
.
begins
(
pArg
,
"-version="
)
>
0
)
{
char
[
]
lVersionString
;
lVersionString
=
pArg
[
9
..
$
]
;
source
.
ActivateVersion
(
lVersionString
)
;
pArg
=
vVersionSwitch
~
lVersionString
;
}
else
if
(
util
.
str
.
begins
(
pArg
,
"-fversion="
)
>
0
)
{
char
[
]
lVersionString
;
lVersionString
=
pArg
[
10
..
$
]
;
source
.
ActivateVersion
(
lVersionString
)
;
pArg
=
vVersionSwitch
~
lVersionString
;
}
else
if
(
pArg
==
"-fdebug"
)
{
source
.
ActivateDebug
(
"1"
)
;
pArg
=
vDebugSwitch
;
}
else
if
(
pArg
==
"-debug"
)
{
source
.
ActivateDebug
(
"1"
)
;
pArg
=
vDebugSwitch
;
}
else
if
(
util
.
str
.
begins
(
pArg
,
"-fdebug="
)
>
0
)
{
char
[
]
lDebugString
;
lDebugString
=
pArg
[
8
..
$
]
;
source
.
ActivateDebug
(
lDebugString
)
;
pArg
=
vDebugSwitch
~
"="
~
lDebugString
;
}
else
if
(
util
.
str
.
begins
(
pArg
,
"-debug="
)
>
0
)
{
char
[
]
lDebugString
;
lDebugString
=
pArg
[
7
..
$
]
;
source
.
ActivateDebug
(
lDebugString
)
;
pArg
=
vDebugSwitch
~
"="
~
lDebugString
;
}
switch
(
pArg
)
{
case
"-full"
:
vForceCompile
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-link"
:
Source
.
WasMainFound
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-nolink"
:
vNoLink
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-lib"
:
vLibraryAction
=
LibOpt
.
Build
;
vBuildArgs
~=
pArg
;
break
;
case
"-nolib"
:
vLibraryAction
=
LibOpt
.
DontBuild
;
vBuildArgs
~=
pArg
;
break
;
case
"-obj"
:
vLibraryAction
=
LibOpt
.
DontBuild
;
vNoLink
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-nounittest"
:
if
(
vSilent
==
false
)
writefln
(
"Note: '-nounittest' ignored. This switch is no longer used."
)
;
break
;
case
"-info"
:
DisplayUsage
(
false
)
;
vBuildArgs
~=
pArg
;
break
;
case
"-silent"
:
vSilent
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-noautoimport"
:
vAutoImports
=
false
;
vBuildArgs
~=
pArg
;
break
;
case
"-nodef"
:
vNoDef
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-nomacro"
:
vMacroInput
=
false
;
vBuildArgs
~=
pArg
;
break
;
case
"-usage"
:
case
"-help"
:
case
"-h"
:
case
"-?"
:
DisplayUsage
(
)
;
vBuildArgs
~=
pArg
;
break
;
case
"-allobj"
:
vAllObjects
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-test"
:
vTestRun
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-cleanup"
:
case
"-clean"
:
vCleanup
=
true
;
vBuildArgs
~=
pArg
;
break
;
case
"-V"
:
vBuildArgs
~=
pArg
;
break
;
case
"-names"
:
vBuildArgs
~=
pArg
;
vNames
=
true
;
break
;
default
:
if
(
pArg
.
length
>
0
)
{
if
(
pArg
[
0
]
==
'-'
)
{
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-LIBOPT*"
)
)
{
vLibrarianOpts
~=
" "
~
pArg
[
7
..
$
]
.
dup
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
util
.
str
.
begins
(
pArg
,
"-LIBPATH="
)
>=
0
)
{
vLibPaths
~=
vConfigSep
~
pArg
[
9
..
$
]
.
dup
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-DCPATH*"
)
)
{
lNewPath
=
pArg
[
7
..
length
]
.
dup
;
if
(
vCompilerPath
==
vConfigPath
)
{
if
(
vVerbose
)
writefln
(
"CFPATH was %s now %s"
,
vConfigPath
,
lNewPath
)
;
vConfigPath
=
lNewPath
;
}
if
(
vVerbose
)
writefln
(
"DCPATH was %s now %s"
,
vCompilerPath
,
lNewPath
)
;
vCompilerPath
=
lNewPath
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-CFPATH*"
)
)
{
if
(
vVerbose
)
writefln
(
"CFPATH was %s now %s"
,
vConfigPath
,
pArg
[
7
..
length
]
)
;
vConfigPath
=
pArg
[
7
..
length
]
.
dup
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-RDF*"
)
)
{
if
(
vVerbose
)
writefln
(
"RDF was %s now %s"
,
vRDFName
,
pArg
[
4
..
$
]
)
;
vRDFName
=
pArg
[
4
..
$
]
.
dup
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
pArg
==
vBuildImportPathSwitch
)
{
vDelayedValue
=
&
lImportSwitch
;
vBuildArgs
~=
pArg
;
break
;
}
else
if
(
(
lCut
=
util
.
str
.
begins
(
pArg
,
vBuildImportPathSwitch
)
)
>=
0
)
{
char
[
]
lRoot
;
foreach
(
char
[
]
lCmdRoot
;
std
.
string
.
split
(
pArg
[
lCut
..
$
]
,
";"
)
)
{
lRoot
=
AddRoot
(
lCmdRoot
)
;
if
(
lRoot
.
length
>
0
)
{
if
(
vVerbose
)
{
writefln
(
"Added root from command line = %s"
,
lRoot
)
;
}
}
}
break
;
}
if
(
util
.
str
.
IsLike
(
pArg
,
std
.
utf
.
toUTF32
(
vRunSwitch
~
"*"
)
)
)
{
vRunParms
~=
pArg
[
vRunSwitch
.
length
..
$
]
~
" "
;
vExecuteProgram
=
true
;
vBuildArgs
~=
pArg
;
break
;
}
version
(
DigitalMars
)
{
if
(
util
.
str
.
IsLike
(
pArg
,
std
.
utf
.
toUTF32
(
vTemporaryPathSwitch
~
"*"
)
)
)
{
char
[
]
lRoot
;
vTemporaryPath
=
pArg
[
vTemporaryPathSwitch
.
length
..
$
]
;
if
(
vTemporaryPath
.
length
>
0
&&
vTemporaryPath
[
$
-
1
..
$
]
!=
std
.
path
.
sep
)
vTemporaryPath
~=
std
.
path
.
sep
;
lRoot
=
AddRoot
(
vTemporaryPath
)
;
if
(
lRoot
.
length
>
0
)
{
if
(
vVerbose
)
{
writefln
(
"Added root from Object Write Path = %s"
,
lRoot
)
;
}
util
.
pathex
.
MakePath
(
lRoot
)
;
}
vBuildArgs
~=
pArg
;
}
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-X*"
)
)
{
vModulesToIgnore
~=
pArg
[
2
..
$
]
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-M*"
)
)
{
vModulesToNotice
~=
pArg
[
2
..
$
]
;
vBuildArgs
~=
pArg
;
break
;
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-T*"
)
)
{
vCommandTargetName
=
pArg
[
2
..
$
]
;
vBuildArgs
~=
pArg
;
break
;
}
version
(
DigitalMars
)
{
if
(
util
.
str
.
IsLike
(
pArg
,
(
vOutFileSwitch
~
"*"
)
)
)
{
vCommandTargetName
=
pArg
[
vOutFileSwitch
.
length
..
$
]
;
vBuildArgs
~=
pArg
;
break
;
}
}
version
(
GNU
)
{
if
(
pArg
==
vOutFileSwitch
)
{
vDelayedValue
=
&
vCommandTargetName
;
vBuildArgs
~=
pArg
;
break
;
}
}
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-R*"
)
)
{
if
(
pArg
.
length
==
2
)
vUseResponseFile
=
(
vUseResponseFile
?
false
:
true
)
;
else
if
(
pArg
[
2
]
==
'y'
)
vUseResponseFile
=
true
;
else
vUseResponseFile
=
false
;
vBuildArgs
~=
pArg
;
break
;
}
version
(
Windows
)
{
if
(
util
.
str
.
IsLike
(
pArg
,
cast
(
dchar
[
]
)
"-gui*"
)
)
{
Source
.
WasMainGUI
=
true
;
vBuildArgs
~=
pArg
;
if
(
pArg
.
length
==
4
)
break
;
if
(
pArg
[
4
]
==
':'
)
vWinVer
=
pArg
[
5
..
length
]
;
else
vWinVer
=
pArg
[
4
..
length
]
;
break
;
}
if
(
pArg
==
"-dll"
)
{
Source
.
WasMainDLL
=
true
;
vBuildArgs
~=
pArg
;
break
;
}
}
AddCompilerArg
(
pArg
)
;
}
else
{
if
(
vDelayedValue
!=
null
)
{
if
(
vDelayedValue
==
&
lImportSwitch
)
{
char
[
]
lRoot
;
foreach
(
char
[
]
lCmdRoot
;
std
.
string
.
split
(
pArg
,
";"
)
)
{
lRoot
=
AddRoot
(
lCmdRoot
)
;
if
(
lRoot
.
length
>
0
)
{
if
(
vVerbose
)
{
writefln
(
"Added root from command line = %s"
,
lRoot
)
;
}
}
}
}
else
{
*
vDelayedValue
=
pArg
;
vBuildArgs
~=
pArg
;
}
vDelayedValue
=
null
;
break
;
}
switch
(
std
.
path
.
getExt
(
pArg
)
)
{
case
""
:
pArg
~=
"."
~
kSrcExtention
;
vCmdLineSourceFiles
~=
pArg
;
break
;
case
kSrcExtention
:
case
kMacroExtention
:
vCmdLineSourceFiles
~=
pArg
;
break
;
default
:
AddLink
(
GetFullPathname
(
pArg
)
)
;
}
if
(
vTargetName
is
null
)
{
vTargetName
=
pArg
;
}
}
break
;
}
}
}
void
GatherOneArg
(
char
[
]
pArg
)
{
static
bool
[
char
[
]
]
lKnownArgs
;
pArg
=
std
.
string
.
strip
(
pArg
)
;
if
(
pArg
.
length
==
0
)
return
;
if
(
(
pArg
==
"-V"
)
||
(
pArg
==
"-v"
)
)
vVerbose
=
true
;
if
(
pArg
.
length
>=
2
&&
pArg
[
0
..
2
]
==
"--"
)
{
pArg
=
pArg
[
1
..
$
]
;
if
(
(
pArg
==
"-V"
)
||
(
pArg
==
"-v"
)
)
vVerbose
=
false
;
for
(
int
i
=
vCombinedArgs
.
length
-
1
;
i
>=
0
;
i
--
)
{
if
(
pArg
[
$
-
1
]
==
'*'
)
{
if
(
vCombinedArgs
[
i
]
.
begins
(
pArg
[
0
..
$
-
1
]
)
>
0
)
{
vCombinedArgs
=
vCombinedArgs
[
0
..
i
]
~
vCombinedArgs
[
i
+
1
..
$
]
;
break
;
}
}
else
if
(
vCombinedArgs
[
i
]
==
pArg
)
{
vCombinedArgs
=
vCombinedArgs
[
0
..
i
]
~
vCombinedArgs
[
i
+
1
..
$
]
;
break
;
}
}
}
else
if
(
pArg
[
0
]
==
'@'
)
ProcessResponseFile
(
pArg
,
vVerbose
)
;
else
if
(
pArg
[
0
]
==
'+'
)
ProcessBuildConfig
(
pArg
,
vVerbose
)
;
else
{
if
(
!
(
pArg
in
lKnownArgs
)
)
{
vCombinedArgs
~=
pArg
;
lKnownArgs
[
pArg
]
=
true
;
}
}
}
void
GatherArgs
(
char
[
]
[
]
pArgs
)
{
ProcessBuildConfig
(
"+"
,
vVerbose
)
;
foreach
(
char
[
]
lArg
;
pArgs
)
{
GatherOneArg
(
lArg
)
;
}
}
void
ProcessMacroDefs
(
bool
pVerbose
)
{
ProcessOneMacroDef
(
pVerbose
,
std
.
path
.
getDirName
(
vAppPath
)
)
;
ProcessOneMacroDef
(
pVerbose
,
vCompilerPath
)
;
}
void
ProcessOneMacroDef
(
bool
pVerbose
,
char
[
]
pPath
)
{
char
[
]
lMacroDefFileName
;
char
[
]
[
]
lMacroDefLines
;
char
[
]
lOpen
;
char
[
]
lClose
;
char
[
]
lEscapeOpen
;
char
[
]
lEscapeClose
;
char
[
]
lCommentLead
;
static
char
[
]
lDefOpen
=
"\""
;
static
char
[
]
lDefClose
=
"\""
;
static
char
[
]
lDefEscapeOpen
=
"\\"
;
static
char
[
]
lDefEscapeClose
=
""
;
static
char
[
]
lDefCommentLead
=
"#"
;
lOpen
=
lDefOpen
;
lClose
=
lDefClose
;
lEscapeOpen
=
lDefEscapeOpen
;
lEscapeClose
=
lDefEscapeClose
;
lCommentLead
=
lDefCommentLead
;
lMacroDefFileName
=
pPath
.
dup
;
if
(
(
lMacroDefFileName
.
length
>
0
)
&&
(
lMacroDefFileName
[
$
-
std
.
path
.
sep
.
length
..
$
]
!=
std
.
path
.
sep
)
)
lMacroDefFileName
~=
std
.
path
.
sep
;
lMacroDefFileName
~=
"build.mdf"
;
if
(
pVerbose
&&
util
.
fileex
.
FileExists
(
lMacroDefFileName
)
)
writefln
(
"Build Macro Definition file %s"
,
lMacroDefFileName
)
;
lMacroDefLines
=
util
.
fileex
.
GetTextLines
(
lMacroDefFileName
,
util
.
fileex
.
GetOpt
.
Always
)
;
foreach
(
char
[
]
lArg
;
lMacroDefLines
)
{
char
[
]
[
]
lOptions
;
lArg
=
ExpandEnvVar
(
lArg
)
;
int
lPos
=
std
.
string
.
find
(
lArg
,
lCommentLead
)
;
if
(
lPos
!=
-
1
)
{
lArg
.
length
=
lPos
;
}
lArg
=
std
.
string
.
strip
(
lArg
)
;
if
(
lArg
.
length
>
1
)
{
if
(
lArg
.
begins
(
"replace "
)
>
0
)
{
int
lStartPos
;
int
lEndPos
;
bool
lEndFound
;
int
lDepthInc
;
int
lDepth
;
int
lDataPos
;
char
[
]
lPattern
;
char
[
]
lResolution
;
lArg
=
std
.
string
.
strip
(
lArg
[
8
..
$
]
)
;
if
(
lOpen
in
vNestedDelim
)
lDepthInc
=
1
;
else
lDepthInc
=
0
;
lStartPos
=
0
;
lEndPos
=
lStartPos
+
lOpen
.
length
;
while
(
(
lEndPos
<
lArg
.
length
)
&&
(
lArg
[
lStartPos
..
lEndPos
]
!=
lOpen
)
)
{
lStartPos
++
;
lEndPos
++
;
}
if
(
lEndPos
>=
lArg
.
length
)
continue
;
lDepth
+=
lDepthInc
;
lDataPos
=
lEndPos
;
lStartPos
=
lDataPos
;
lEndPos
=
lStartPos
+
lClose
.
length
;
while
(
(
lEndPos
<
lArg
.
length
)
&&
(
lArg
[
lStartPos
..
lEndPos
]
!=
lClose
)
)
{
lStartPos
++
;
lEndPos
++
;
}
if
(
lEndPos
>=
lArg
.
length
)
continue
;
lPattern
=
std
.
string
.
strip
(
lArg
[
lDataPos
..
lStartPos
]
)
;
lStartPos
=
lEndPos
;
lEndPos
=
lStartPos
+
lOpen
.
length
;
while
(
(
lEndPos
<
lArg
.
length
)
&&
(
lArg
[
lStartPos
..
lEndPos
]
!=
lOpen
)
)
{
lStartPos
++
;
lEndPos
++
;
}
if
(
lEndPos
>=
lArg
.
length
)
continue
;
lDepth
+=
lDepthInc
;
lDataPos
=
lEndPos
;
lStartPos
=
lDataPos
;
lEndPos
=
lStartPos
+
lClose
.
length
;
while
(
(
lEndPos
<
lArg
.
length
)
&&
(
lArg
[
lStartPos
..
lEndPos
]
!=
lClose
)
)
{
lStartPos
++
;
lEndPos
++
;
}
if
(
lEndPos
>
lArg
.
length
)
continue
;
lResolution
=
std
.
string
.
strip
(
lArg
[
lDataPos
..
lStartPos
]
)
;
vSubstitutions
.
length
=
vSubstitutions
.
length
+
1
;
vSubstitutions
[
$
-
1
]
.
Pattern
=
lPattern
;
vSubstitutions
[
$
-
1
]
.
Resolution
=
lResolution
;
vSubstitutions
[
$
-
1
]
.
EscapeOpen
=
lEscapeOpen
;
vSubstitutions
[
$
-
1
]
.
EscapeClose
=
lEscapeClose
;
}
else
if
(
lArg
.
begins
(
"delim "
)
>
0
)
{
lArg
=
std
.
string
.
strip
(
lArg
[
6
..
$
]
)
;
lOptions
=
std
.
string
.
split
(
lArg
)
;
foreach
(
char
[
]
lOption
;
lOptions
)
{
if
(
lOption
==
"std"
)
{
lOpen
=
lDefOpen
;
lClose
=
lDefClose
;
lEscapeOpen
=
lDefEscapeOpen
;
lEscapeClose
=
lDefEscapeClose
;
lCommentLead
=
lDefCommentLead
;
}
else
{
char
[
]
[
]
lKeyValue
;
lKeyValue
=
std
.
string
.
split
(
lOption
,
"="
)
;
switch
(
lKeyValue
[
0
]
)
{
case
"open"
:
lOpen
=
lKeyValue
[
1
]
;
break
;
case
"close"
:
lClose
=
lKeyValue
[
1
]
;
break
;
case
"escapeopen"
:
lEscapeOpen
=
lKeyValue
[
1
]
;
break
;
case
"escapeclose"
:
lEscapeClose
=
lKeyValue
[
1
]
;
break
;
case
"comment"
:
lCommentLead
=
lKeyValue
[
1
]
;
break
;
default
:
if
(
pVerbose
)
writefln
(
"Bad Macro 'delim' option '%s'"
,
lOption
)
;
break
;
}
}
}
}
else
if
(
vVerbose
)
{
writefln
(
"Bad configuration command '%s'"
,
lArg
)
;
}
}
}
}
void
ProcessBuildConfig
(
char
[
]
pArg
,
bool
pVerbose
)
{
ProcessOneBuildConfig
(
pArg
,
pVerbose
,
std
.
path
.
getDirName
(
vAppPath
)
)
;
ProcessOneBuildConfig
(
pArg
,
pVerbose
,
vCompilerPath
)
;
}
void
ProcessOneBuildConfig
(
char
[
]
pArg
,
bool
pVerbose
,
char
[
]
pPath
)
{
char
[
]
lConfigFileName
;
char
[
]
[
]
lConfigLines
;
bool
lFoundGroup
;
lConfigFileName
=
pPath
.
dup
;
if
(
(
lConfigFileName
.
length
>
0
)
&&
(
lConfigFileName
[
$
-
std
.
path
.
sep
.
length
..
$
]
!=
std
.
path
.
sep
)
)
lConfigFileName
~=
std
.
path
.
sep
;
lConfigFileName
~=
"build.cfg"
;
if
(
pVerbose
&&
util
.
fileex
.
FileExists
(
lConfigFileName
)
)
writefln
(
"Build Configuration file %s [%s]"
,
lConfigFileName
,
pArg
)
;
lConfigLines
=
util
.
fileex
.
GetTextLines
(
lConfigFileName
,
util
.
fileex
.
GetOpt
.
Always
)
;
if
(
pArg
.
length
==
1
)
lFoundGroup
=
true
;
else
{
lFoundGroup
=
false
;
pArg
=
pArg
[
1
..
$
]
;
}
foreach
(
char
[
]
lArg
;
lConfigLines
)
{
lArg
=
ExpandEnvVar
(
lArg
)
;
if
(
!
lFoundGroup
)
{
if
(
lArg
==
"["
~
pArg
~
"]"
)
{
lFoundGroup
=
true
;
continue
;
}
}
if
(
lFoundGroup
)
{
int
lPos
=
std
.
string
.
find
(
lArg
,
"#"
)
;
if
(
lPos
!=
-
1
)
{
lArg
.
length
=
lPos
;
}
lArg
=
std
.
string
.
strip
(
lArg
)
;
if
(
lArg
.
length
>
1
)
{
if
(
(
lArg
[
0
]
==
'['
)
&&
(
lArg
[
$
-
1
]
==
']'
)
)
break
;
if
(
pVerbose
)
writefln
(
"Build Configuration file arg: %s"
,
lArg
)
;
while
(
(
lPos
=
find
(
lArg
,
"{Group}"
)
)
!=
-
1
)
{
lArg
=
lArg
[
0
..
lPos
]
~
pArg
~
lArg
[
lPos
+
7
..
$
]
;
}
if
(
lArg
.
begins
(
"CMDLINE="
)
>
0
)
{
int
lStartPos
;
int
lEndPos
;
bool
lEndFound
;
lArg
=
std
.
string
.
strip
(
lArg
[
8
..
$
]
)
;
lStartPos
=
0
;
lEndPos
=
0
;
lEndFound
=
false
;
while
(
lEndPos
<
lArg
.
length
)
{
if
(
!
lEndFound
)
{
if
(
lArg
[
lEndPos
]
==
' '
)
{
lEndFound
=
true
;
}
}
else
{
if
(
find
(
"-+@"
,
lArg
[
lEndPos
..
lEndPos
+
1
]
)
!=
-
1
)
{
GatherOneArg
(
lArg
[
lStartPos
..
lEndPos
]
)
;
lStartPos
=
lEndPos
;
lEndFound
=
false
;
}
}
lEndPos
++
;
}
if
(
lStartPos
!=
lEndPos
)
GatherOneArg
(
lArg
[
lStartPos
..
lEndPos
]
)
;
}
else
if
(
lArg
.
begins
(
"LIBCMD="
)
>
0
)
{
int
lPos
;
while
(
(
lPos
=
find
(
lArg
,
"\""
)
)
!=
-
1
)
{
lArg
=
lArg
[
0
..
lPos
]
~
lArg
[
lPos
+
1
..
$
]
;
}
vLibrarianPath
=
std
.
path
.
getDirName
(
lArg
[
7
..
$
]
)
~
std
.
path
.
sep
;
vLibrarianPath
=
util
.
pathex
.
CanonicalPath
(
vLibrarianPath
)
;
vLibrarian
=
std
.
path
.
getBaseName
(
lArg
[
7
..
$
]
)
;
if
(
vVerbose
)
{
writefln
(
" librarian path %s"
,
vLibrarianPath
)
;
writefln
(
" librarian is %s"
,
vLibrarian
)
;
}
}
else
if
(
vVerbose
)
{
writefln
(
"Bad configuration command '%s'"
,
lArg
)
;
}
}
}
}
}
