XQuilla/wintools/genproject.xq
2020-02-17 22:17:06 +01:00

416 lines
16 KiB
Text

(:
* IMPORTANT: this file is shared (identical) between the BDB XML and XQilla
* projects. It should not be changed independently or in any way that makes
* it project-dependent.
*
* TBD:
* 1. Could drive the remaining variables, including Visual Studio
* variables, off of the xml file and provide the XML input
* file as an external variable to the query. E.g. some projects
* may want to parameterize the optimization and warnings levels
* 2. Generate AdditionalIncludeDirectories based on the <depends> elements for
* projects rather than just including "all"
:)
declare variable $projectFile external;
declare variable $outputPath external;
declare variable $projectDoc := doc($projectFile);
declare variable $sourcePath := $projectDoc/projects/variable[@name="sourcePath"];
(: Visual Studio Variables --relatively static :)
declare variable $debugOptLevel := "0"; (: VS -- no optimization :)
declare variable $releaseOptLevel := "2"; (: VS -- level 2 opt :)
declare variable $warnLevel := "3"; (: VS warning level :)
declare variable $appType := "1"; (: VS type 1 is a program :)
declare variable $dllType := "2"; (: VS type 2 is a DLL :)
declare variable $staticType := "4"; (: VS type 4 is a static lib :)
declare variable $debugInfo := "3"; (: VS debug information format :)
declare variable $libExtension := ".lib";
(: formatting :)
declare function local:indent($n)
{
concat("&#xa;",string-join(for $i in (1 to $n) return " ", ""))
};
(: is it a DLL, Application, or static library? :)
declare function local:configurationType($projectType)
{
if ($projectType eq "dll") then $dllType
else if ($projectType eq "app") then $appType
else if ($projectType eq "static_lib") then $staticType
else if ($projectType eq "static_app") then $appType
else error(QName("", "dbxml"), "Unknown project type")
};
(: "normalize" Windows file paths :)
declare function local:windowsPath($path) as xs:string
{
translate($path,"/","\\")
};
(: debug vs release :)
declare function local:isDebug($config) as xs:boolean
{
contains($config,"Debug")
};
declare function local:isRelease($config) as xs:boolean
{
contains($config,"Release")
};
(: machine-target-dependent link options :)
declare function local:addLinkOptions($project, $platform, $config)
{
let $machine := if (contains($platform,"Win32")) then "/machine:x86"
else concat("/machine:",$platform)
let $opt := string-join(($machine,$project/options/link[contains(@config,$config)])," ")
return if (not($opt eq "")) then attribute{"AdditionalOptions"}{$opt}
else ()
};
declare function local:addDebugInformation($config)
{
attribute{"DebugInformationFormat"}{$debugInfo},
if (local:isDebug($config)) then attribute{"BasicRuntimeChecks"}{"3"} else ()
};
declare function local:generateCompilerPreprocessorDefs($project, $config)
{
let $generic := $projectDoc/projects/preprocessor[@config="all" or contains($config,@config)]
let $proj := $project/preprocessor[@config="all" or contains(@config,$config)]
let $type := $projectDoc/projects/preprocessor[@config=$project/type]
return string-join(($generic,$proj,$type),";")
};
(:
declare function local:generateResourcePreprocessorDefs($config)
{
let $dbg := if (local:isDebug($config)) then "_DEBUG" else "NDEBUG"
return concat($dbg,";_CRT_SECURE_NO_DEPRECATE=1")
};
:)
(: Optimization level :)
declare function local:optLevel($config)
{
if (local:isDebug($config)) then $debugOptLevel
else $releaseOptLevel
};
(: MDd is 3, MD is 2, MTd is 1, MT is 0 :)
declare function local:runtimeLibrary($config,$static as xs:boolean)
{
if (local:isDebug($config)) then
if ($static) then "1" else"3"
else
if ($static) then "0" else"2"
};
declare function local:getLibName($name, $config)
{
$projectDoc/projects/library[@name=$name]/libname[@config=$config]
};
declare function local:makeStaticOutputFile($project, $config)
{
attribute{"OutputFile"}
{concat("$(OutDir)/", local:getLibName($project/@name, $config),".lib")
}
};
declare function local:makeImportLibrary($project, $config)
{
if ($project/type eq "dll") then
attribute{"ImportLibrary"}{concat("$(OutDir)/", local:getLibName($project/@name, $config),".lib")}
else ()
};
declare function local:makeModuleDefinition($project, $config)
{
if (not(empty($project/moddef))) then
attribute{"ModuleDefinitionFile"}{local:windowsPath(concat($sourcePath,$project/moddef/@file))}
else ()
};
declare function local:makeOutputPDBFile($project, $config)
{
attribute{"ProgramDatabaseFile"}
{
if ($project/type eq "dll") then
concat("$(OutDir)/", local:getLibName($project/@name, $config),".pdb")
else
concat("$(OutDir)/",if (not(empty($project/@output))) then $project/@output else $project/@name,".pdb")
}
};
declare function local:makeOutputFile($project, $config)
{
attribute{"OutputFile"}
{
if ($project/type eq "dll") then
concat("$(OutDir)/", local:getLibName($project/@name, $config), ".dll")
else
concat("$(OutDir)/",if (not(empty($project/@output))) then $project/@output else $project/@name,".exe")
}
};
(: The simple thing is to add all libraries for all projects :)
declare function local:addLibraryDependencies($project,$config)
{
attribute{"AdditionalDependencies"}{string-join(for $dep in $project/depends
return concat(local:getLibName($dep, $config),".lib")," ")}
};
declare function local:makeLibraryDirectory($lib,$platform,$config,$vsversion)
{
for $dir in $lib/platform[contains(@name,$platform)]/config[$config=./@type]/libdir
return
if (not(empty($lib/libbase[@vsver=$vsversion]))) then
concat($lib/libbase[@vsver=$vsversion],"/", $dir)
else $dir
};
(: The simple thing is to add all libraries for all projects :)
declare function local:addLibraryDirectories($project,$platform,$config,$vsversion)
{
attribute{"AdditionalLibraryDirectories"}{string-join(for $dep in $project/depends
return local:makeLibraryDirectory($projectDoc/projects/library[@name=$dep],$platform,$config,$vsversion),";")}
};
(: The simple thing is to add all libraries for all projects :)
declare function local:addIncludeDirectories($project,$config)
{
let $incref := for $inc in $project/include[@type="ref"] return $projectDoc/projects/include[@name=$inc]
let $increl := $project/include[@type="rel"]
return
attribute{"AdditionalIncludeDirectories"}{string-join(($incref,$increl),",")}
};
(: look for project-specific tool, then a type-specific event :)
declare function local:generatePostBuildEvent($project, $config)
{
local:indent(6),<Tool>
{attribute{"Name"}{"VCPostBuildEventTool"}}
{if (not(empty($project/event[@name="postbuild"]))) then
(attribute{"CommandLine"}{$project/event[@name="postbuild"]/command[@config=$config]},
attribute{"Description"}{$project/event[@name="postbuild"]/description})
else let $ev := $projectDoc/projects/event[@name="postbuild" and @type=$project/type]
return if (not(empty($ev))) then
(attribute{"CommandLine"}{replace($ev/command[@config=$config],"@pname@",if (not(empty($project/@output))) then $project/@output else $project/@name)},
attribute{"Description"}{$ev/description})
else ()
}
</Tool>
};
declare function local:generateCustomBuildTool($project, $config)
{
local:indent(6),<Tool>
{attribute{"Name"}{"VCCustomBuildTool"}}
{if (not(empty($project/event[@name="custom"]))) then
(attribute{"CommandLine"}{$project/event[@name="custom"]/command[contains(@config,$config)]},
attribute{"Outputs"}{$project/event[@name="custom"]/output})
else ()}
</Tool>
};
(:
static build of libraries; at this time it does *not* add additional
dependent libraries. This means that applications need to include them
for the time being.
:)
declare function local:generateConfigLibrarian($project, $config)
{
local:indent(6),<Tool>
{attribute{"Name"}{"VCLibrarianTool"}}
{local:makeStaticOutputFile($project,$config)}
</Tool>
};
declare function local:generateConfigLinkerAndMidl($project, $platform, $config, $vsversion)
{
local:indent(6),<Tool>
{attribute{"Name"}{"VCLinkerTool"}}
{local:addLinkOptions($project, $platform, $config)}
{local:addLibraryDependencies($project,$config)}
{local:addLibraryDirectories($project,$platform,$config,$vsversion)}
{local:makeOutputFile($project, $config)}
{local:makeOutputPDBFile($project, $config)}
{attribute{"LinkIncremental"}{"1"}}
{attribute{"GenerateDebugInformation"}{"TRUE"}}
{attribute{"SuppressStartupBanner"}{"TRUE"}}
{attribute{"OptimizeReferences"}{"2"}}
{local:makeImportLibrary($project,$config)}
{local:makeModuleDefinition($project,$config)}
{attribute{"TargetMachine"}{"0"}}
</Tool>
};
declare function local:generateConfigCompiler($project, $platform, $config, $static as xs:boolean, $vsversion)
{
local:indent(6),<Tool>
{attribute{"Name"}{"VCCLCompilerTool"}}
{attribute{"Optimization"}{local:optLevel($config)}}
{attribute{"MinimalRebuild"}{"TRUE"}}
{if (local:isRelease($config)) then attribute{"InlineFunctionExpansion"}{"1"} else ()}
{local:addIncludeDirectories($project,$config)}
{attribute{"PreprocessorDefinitions"}{local:generateCompilerPreprocessorDefs($project, $config)}}
{attribute{"StringPooling"}{"TRUE"}}
{if (not(empty($project/options/rtti))) then attribute{"RuntimeTypeInfo"}{"TRUE"} else ()}
{attribute{"RuntimeLibrary"}{local:runtimeLibrary($config,$static)}}
{if (local:isRelease($config)) then attribute{"EnableFunctionLevelLinking"}{"TRUE"} else ()}
{attribute{"UsePrecompiledHeader"}{"0"}}
{if ($project/@name eq "dbxml") then attribute{"PrecompiledHeaderThrough"}{"DbXmlInternal.hpp"} else ()}
{attribute{"PrecompiledHeaderFile"}{concat("./$(OutDir)/",$project/@name,".pch")}}
{attribute{"AssemblerListingLocation"}{"./$(OutDir)/"}}
{attribute{"ObjectFile"}{"./$(OutDir)/"}}
{attribute{"WarningLevel"}{$warnLevel}}
{if (not($vsversion eq "8.00") and not($project/options/nowp64)) then attribute{"Detect64BitPortabilityProblems"}{"TRUE"} else ()}
{attribute{"SuppressStartupBanner"}{"TRUE"}}
{local:addDebugInformation($config)}
{attribute{"CompileAs"}{"0"}}
</Tool>
};
declare function local:generateConfigBoilerplate($config)
{
local:indent(6),<Tool Name="VCPreBuildEventTool"/>,
local:indent(6),<Tool Name="VCPreLinkEventTool"/>,
local:indent(6),<Tool Name="VCResourceCompilerTool"/>,
local:indent(6),<Tool Name="VCXMLDataGeneratorTool"/>,
local:indent(6),<Tool Name="VCManagedWrapperGeneratorTool"/>,
local:indent(6),<Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
};
(: use "platform/configuration" :)
declare function local:generateOutputDirectory($platform,$config,$static,$vsversion)
{
let $outputBase := $projectDoc/projects/variable[@name=concat("outputBase.", $vsversion)]
return attribute{"OutputDirectory"}{local:windowsPath(concat($outputBase,"$(PlatformName)","/",string-join(tokenize($config," "),"_"),$static))}
};
declare function local:generateConfig($project, $platform, $config, $vsversion)
{
local:indent(4),<Configuration>
{attribute{"Name"}{concat($config,"|",$platform)}}
{local:generateOutputDirectory($platform,$config,"", $vsversion)}
{attribute{"IntermediateDirectory"}{concat("./$(OutDir)/",$project/@name)}}
{attribute{"ConfigurationType"}{local:configurationType($project/type)}}
{attribute{"UseOfMFC"}{"0"}}
{attribute{"ATLMinimizesCRunTimeLibraryUsage"}{"FALSE"}}
{attribute{"CharacterSet"}{"2"}}
{local:generateConfigBoilerplate($config)}
{local:generateConfigCompiler($project, $platform, $config,false(),$vsversion)}
{local:generateConfigLinkerAndMidl($project, $platform, $config, $vsversion)}
{local:generatePostBuildEvent($project,if (local:isDebug($config)) then "Debug" else "Release")}
{local:generateCustomBuildTool($project,if (local:isDebug($config)) then "Debug" else "Release")}
</Configuration>
};
declare function local:generateStaticConfig($project, $platform, $config, $vsversion)
{
local:indent(4),<Configuration>
{attribute{"Name"}{concat($config,"|",$platform)}}
{local:generateOutputDirectory($platform,$config,"_static", $vsversion)}
{attribute{"IntermediateDirectory"}{concat("./$(OutDir)/",$project/@name)}}
{attribute{"ConfigurationType"}{local:configurationType($project/type)}}
{attribute{"UseOfMFC"}{"0"}}
{attribute{"ATLMinimizesCRunTimeLibraryUsage"}{"FALSE"}}
{attribute{"CharacterSet"}{"2"}}
{local:generateConfigBoilerplate($config)}
{local:generateConfigCompiler($project, $platform, $config,true(),$vsversion)}
{if (contains($project/type,"lib")) then
local:generateConfigLibrarian($project, $config)
else
local:generateConfigLinkerAndMidl($project, $platform, $config, $vsversion)
}
</Configuration>
};
declare function local:generateRcFile($file, $vsversion)
{
local:indent(4),<File RelativePath="{local:windowsPath(concat($sourcePath,$file/@name))}">
{ for $platform in local:getPlatforms($vsversion) return
for $config in ("Debug","Release") return
(local:indent(6),<FileConfiguration Name="{concat($config,"|",$platform)}">
<Tool Name="VCResourceCompilerTool" PreprocessorDefinitions="{concat(if ($config="Debug") then "_DEBUG" else "NDEBUG",";","$(NoInherit))")}"/>
{local:indent(6)}</FileConfiguration>)
}
{local:indent(4)}</File>
};
declare function local:generateFilesNoFilter($project, $vsversion)
{
for $file in $project/files/file
return if (ends-with($file/@name,".rc")) then local:generateRcFile($file, $vsversion)
else (local:indent(4),<File RelativePath="{local:windowsPath(concat($sourcePath,$file/@name))}"/>)
};
declare function local:generateFilesWithFilter($project,$filter,$vsversion)
{
for $file in $project/files/filter[@name=$filter]/file
return if (ends-with($file/@name,".rc")) then local:generateRcFile($file, $vsversion)
else (local:indent(6),<File RelativePath="{local:windowsPath(concat($sourcePath,$file/@name))}"/>)
};
declare function local:generateFiles($project, $vsversion)
{
let $filters := $project/files/filter/@name
return if (empty($filters)) then
local:generateFilesNoFilter($project, $vsversion)
else
for $filter in $filters
return (local:indent(4),<Filter Name="{$filter}" Filter="">
{local:generateFilesWithFilter($project,$filter,$vsversion)}
{local:indent(4)}</Filter>)
};
declare function local:getGuid($project)
{
concat("{",$project/@guid,"}")
};
declare function local:getPlatforms($version)
{
if ($version eq "7.10") then ("Win32")
else ("Win32", "x64", "IA64")
};
declare function local:getOutputName($project, $vsversion)
{
let $vsname := if($vsversion = "7.10") then "VC7.1" else "VC8"
return
concat($outputPath, "/", $vsname, "/", $project/@name, ".vcproj")
};
for $vsversion in distinct-values($projectDoc//libbase/@vsver)
for $project in $projectDoc/projects/project
let $static := contains($project/@name,"static")
let $proj := if ($static) then $projectDoc/projects/project[@name=substring-before($project/@name,"_static")] else $project
return
put(<VisualStudioProject
ProjectType="Visual C++"
Version="{$vsversion}"
Name="{string($project/@name)}"
ProjectGUID="{local:getGuid($project)}">
{local:indent(2)}<Platforms>
{local:indent(4)}<Platform Name="Win32"/>
{local:indent(4)}<Platform Name="x64"/>
{local:indent(4)}<Platform Name="IA64"/>
{local:indent(2)}</Platforms>
{local:indent(2)}<Configurations>
{
for $platform in local:getPlatforms($vsversion) return
for $config in ("Debug","Release")
return if ($static) then local:generateStaticConfig($project, $platform, $config, $vsversion)
else local:generateConfig($project, $platform, $config, $vsversion)
}
{local:indent(2)}</Configurations>
{local:indent(2)}<References/>
{local:indent(2)}<Files>
{local:generateFiles($proj, $vsversion)}
{local:indent(2)}</Files>
{local:indent(2)}<Globals/>
{"&#xa;"}</VisualStudioProject>, local:getOutputName($project, $vsversion))