Example #1
0
        /// <inheritdoc />
        public override void PostBuild(TaskGraph graph, BuildOptions buildOptions)
        {
            base.PostBuild(graph, buildOptions);

            // If building engine executable for platform doesn't support referencing it when linking game shared libraries
            if (UseSeparateMainExecutable(buildOptions))
            {
                // Build additional executable with Main module only that uses shared library
                using (new ProfileEventScope("BuildExecutable"))
                {
                    BuildMainExecutable(graph, buildOptions);
                }

                // Restore state from PreBuild
                Modules.Add("Main");
            }

            // Mono on Linux is using dynamic linking and needs additional link files
            if (buildOptions.Platform.Target == TargetPlatform.Linux && Platform.BuildTargetPlatform == TargetPlatform.Linux && !IsPreBuilt)
            {
                var task = graph.Add <Task>();
                task.PrerequisiteFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so"));
                task.ProducedFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so.1"));
                task.WorkingDirectory = buildOptions.OutputFolder;
                task.CommandPath      = "ln";
                task.CommandArguments = "-s -f libmonosgen-2.0.so libmonosgen-2.0.so.1";
                task = graph.Add <Task>();
                task.PrerequisiteFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so"));
                task.ProducedFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so.1.0.0"));
                task.WorkingDirectory = buildOptions.OutputFolder;
                task.CommandPath      = "ln";
                task.CommandArguments = "-s -f libmonosgen-2.0.so libmonosgen-2.0.so.1.0.0";
            }
        }
Example #2
0
        /// <summary>
        /// Links the files into an archive (static library).
        /// </summary>
        protected virtual Task CreateArchive(TaskGraph graph, BuildOptions options, string outputFilePath)
        {
            var linkEnvironment = options.LinkEnv;
            var task            = graph.Add <LinkTask>();

            // Setup arguments
            var args = new List <string>();

            {
                args.Add("rcs");

                args.Add(string.Format("-o \"{0}\"", outputFilePath));
            }
            SetupArchiveFilesArgs(graph, options, args, outputFilePath);

            // Input files
            task.PrerequisiteFiles.AddRange(linkEnvironment.InputFiles);
            foreach (var file in linkEnvironment.InputFiles)
            {
                args.Add(string.Format("\"{0}\"", file.Replace('\\', '/')));
            }

            // Use a response file (it can contain any commands that you would specify on the command line)
            bool   useResponseFile = true;
            string responseFile    = null;

            if (useResponseFile)
            {
                responseFile = Path.Combine(options.IntermediateFolder, Path.GetFileName(outputFilePath) + ".response");
                task.PrerequisiteFiles.Add(responseFile);
                Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));
            }

            // Link object into archive
            task.WorkingDirectory = options.WorkingDirectory;
            task.CommandPath      = ArPath;
            task.CommandArguments = useResponseFile ? string.Format("@\"{0}\"", responseFile) : string.Join(" ", args);
            task.Cost             = task.PrerequisiteFiles.Count;
            task.ProducedFiles.Add(outputFilePath);

            // Generate an index to the contents of an archive

            /*task = graph.Add<LinkTask>();
             * task.CommandPath = RanlibPath;
             * task.CommandArguments = string.Format("\"{0}\"", outputFilePath);
             * task.InfoMessage = "Linking " + outputFilePath;
             * task.PrerequisiteFiles.Add(outputFilePath);
             * task.ProducedFiles.Add(outputFilePath);*/

            return(task);
        }
Example #3
0
        /// <inheritdoc />
        public override void PreBuild(TaskGraph graph, BuildOptions options)
        {
            base.PreBuild(graph, options);

            // Compile and include resource file if need to
            if (options.Target.Win32ResourceFile != null && !options.Target.IsPreBuilt && options.Target.OutputType == TargetOutputType.Executable)
            {
                var task       = graph.Add <CompileCppTask>();
                var args       = new List <string>();
                var sourceFile = options.Target.Win32ResourceFile;

                // Suppress Startup Banner
                args.Add("/nologo");

                // Language
                args.Add("/l 0x0409");

                // Add preprocessor definitions
                foreach (var definition in options.CompileEnv.PreprocessorDefinitions)
                {
                    args.Add(string.Format("/D \"{0}\"", definition));
                }

                // Add include paths
                foreach (var includePath in options.CompileEnv.IncludePaths)
                {
                    AddIncludePath(args, includePath);
                }

                // Add the resource file to the produced item list
                var outputFile = Path.Combine(options.IntermediateFolder, Path.GetFileNameWithoutExtension(sourceFile) + ".res");
                args.Add(string.Format("/Fo\"{0}\"", outputFile));
                options.LinkEnv.InputFiles.Add(outputFile);

                // Request included files to exist
                var includes = IncludesCache.FindAllIncludedFiles(sourceFile);
                task.PrerequisiteFiles.AddRange(includes);

                // Add the source file
                args.Add(string.Format("\"{0}\"", sourceFile));
                task.ProducedFiles.Add(outputFile);

                task.WorkingDirectory = options.WorkingDirectory;
                task.CommandPath      = _resourceCompilerPath;
                task.CommandArguments = string.Join(" ", args);
                task.PrerequisiteFiles.Add(sourceFile);
                task.Cost = 1;
            }
        }
Example #4
0
        /// <inheritdoc />
        public override void LinkFiles(TaskGraph graph, BuildOptions options, string outputFilePath)
        {
            outputFilePath = outputFilePath.Replace('\\', '/');

            Task linkTask;

            switch (options.LinkEnv.Output)
            {
            case LinkerOutput.Executable:
            case LinkerOutput.SharedLibrary:
                linkTask = CreateBinary(graph, options, outputFilePath);
                break;

            case LinkerOutput.StaticLibrary:
            case LinkerOutput.ImportLibrary:
                linkTask = CreateArchive(graph, options, outputFilePath);
                break;

            default: throw new ArgumentOutOfRangeException();
            }

            if (!options.LinkEnv.DebugInformation)
            {
                // Strip debug symbols
                var task = graph.Add <Task>();
                task.ProducedFiles.Add(outputFilePath);
                task.WorkingDirectory = options.WorkingDirectory;
                task.CommandPath      = StripPath;
                task.CommandArguments = string.Format("--strip-debug \"{0}\"", outputFilePath);
                task.InfoMessage      = "Striping " + outputFilePath;
                task.Cost             = 1;
                task.DisableCache     = true;
                task.DependentTasks   = new HashSet <Task>();
                task.DependentTasks.Add(linkTask);
            }
        }
Example #5
0
        /// <summary>
        /// Links the files into a binary (executable file or dynamic library).
        /// </summary>
        protected virtual Task CreateBinary(TaskGraph graph, BuildOptions options, string outputFilePath)
        {
            var linkEnvironment = options.LinkEnv;
            var task            = graph.Add <LinkTask>();

            // Setup arguments
            var args = new List <string>();

            {
                args.Add(string.Format("-o \"{0}\"", outputFilePath));

                if (!options.LinkEnv.DebugInformation)
                {
                    args.Add("-Wl,--strip-debug");
                }

                // TODO: linkEnvironment.LinkTimeCodeGeneration
                // TODO: linkEnvironment.Optimization
                // TODO: linkEnvironment.UseIncrementalLinking
            }
            SetupLinkFilesArgs(graph, options, args, outputFilePath);

            args.Add("-Wl,--start-group");

            // Input libraries
            var libraryPaths = new HashSet <string>();

            foreach (var library in linkEnvironment.InputLibraries)
            {
                var dir = Path.GetDirectoryName(library);
                var ext = Path.GetExtension(library);
                if (string.IsNullOrEmpty(dir))
                {
                    args.Add(string.Format("\"-l{0}\"", library));
                }
                else if (string.IsNullOrEmpty(ext))
                {
                    // Skip executable
                }
                else if (ext == ".so")
                {
                    // Link against dynamic library
                    task.PrerequisiteFiles.Add(library);
                    libraryPaths.Add(dir);
                    args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
                }
                else
                {
                    task.PrerequisiteFiles.Add(library);
                    args.Add(string.Format("\"{0}\"", GetLibName(library)));
                }
            }
            foreach (var library in options.Libraries)
            {
                var dir = Path.GetDirectoryName(library);
                var ext = Path.GetExtension(library);
                if (string.IsNullOrEmpty(dir))
                {
                    args.Add(string.Format("\"-l{0}\"", library));
                }
                else if (string.IsNullOrEmpty(ext))
                {
                    // Skip executable
                }
                else if (ext == ".so")
                {
                    // Link against dynamic library
                    task.PrerequisiteFiles.Add(library);
                    libraryPaths.Add(dir);
                    args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
                }
                else
                {
                    task.PrerequisiteFiles.Add(library);
                    args.Add(string.Format("\"{0}\"", GetLibName(library)));
                }
            }

            // Input files
            task.PrerequisiteFiles.AddRange(linkEnvironment.InputFiles);
            foreach (var file in linkEnvironment.InputFiles)
            {
                args.Add(string.Format("\"{0}\"", file.Replace('\\', '/')));
            }

            // Additional lib paths
            libraryPaths.AddRange(linkEnvironment.LibraryPaths);
            foreach (var path in libraryPaths)
            {
                args.Add(string.Format("-L\"{0}\"", path.Replace('\\', '/')));
            }

            args.Add("-Wl,--end-group");

            // Use a response file (it can contain any commands that you would specify on the command line)
            bool   useResponseFile = true;
            string responseFile    = null;

            if (useResponseFile)
            {
                responseFile = Path.Combine(options.IntermediateFolder, Path.GetFileName(outputFilePath) + ".response");
                task.PrerequisiteFiles.Add(responseFile);
                Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));
            }

            // Link
            task.WorkingDirectory = options.WorkingDirectory;
            task.CommandPath      = LdPath;
            task.CommandArguments = useResponseFile ? string.Format("@\"{0}\"", responseFile) : string.Join(" ", args);
            task.InfoMessage      = "Linking " + outputFilePath;
            task.Cost             = task.PrerequisiteFiles.Count;
            task.ProducedFiles.Add(outputFilePath);

            return(task);
        }
Example #6
0
        /// <inheritdoc />
        public override CompileOutput CompileCppFiles(TaskGraph graph, BuildOptions options, List <string> sourceFiles, string outputPath)
        {
            var compileEnvironment = options.CompileEnv;
            var output             = new CompileOutput();

            // Setup arguments shared by all source files
            var commonArgs = new List <string>();

            SetupCompileCppFilesArgs(graph, options, commonArgs, outputPath);
            {
                commonArgs.Add("-c");
                commonArgs.Add("-pipe");
                commonArgs.Add("-x");
                commonArgs.Add("c++");
                commonArgs.Add("-std=c++14");

                commonArgs.Add("-Wdelete-non-virtual-dtor");
                commonArgs.Add("-fno-math-errno");
                commonArgs.Add("-fdiagnostics-format=msvc");

                if (Architecture == TargetArchitecture.ARM || Architecture == TargetArchitecture.ARM64)
                {
                    commonArgs.Add("-fsigned-char");
                }

                if (compileEnvironment.RuntimeTypeInfo)
                {
                    commonArgs.Add("-frtti");
                }
                else
                {
                    commonArgs.Add("-fno-rtti");
                }

                if (compileEnvironment.TreatWarningsAsErrors)
                {
                    commonArgs.Add("-Wall -Werror");
                }

                // TODO: compileEnvironment.IntrinsicFunctions
                // TODO: compileEnvironment.FunctionLevelLinking
                // TODO: compileEnvironment.FavorSizeOrSpeed
                // TODO: compileEnvironment.RuntimeChecks
                // TODO: compileEnvironment.StringPooling
                // TODO: compileEnvironment.BufferSecurityCheck

                if (compileEnvironment.DebugInformation)
                {
                    commonArgs.Add("-glldb");
                }

                commonArgs.Add("-pthread");

                if (compileEnvironment.Optimization)
                {
                    commonArgs.Add("-O2");
                }
                else
                {
                    commonArgs.Add("-O0");
                }

                if (!compileEnvironment.Inlining)
                {
                    commonArgs.Add("-fno-inline-functions");
                    commonArgs.Add("-fno-inline");
                }

                if (compileEnvironment.EnableExceptions)
                {
                    commonArgs.Add("-fexceptions");
                }
                else
                {
                    commonArgs.Add("-fno-exceptions");
                }
            }

            // Add preprocessor definitions
            foreach (var definition in compileEnvironment.PreprocessorDefinitions)
            {
                commonArgs.Add(string.Format("-D \"{0}\"", definition));
            }

            // Add include paths
            foreach (var includePath in compileEnvironment.IncludePaths)
            {
                commonArgs.Add(string.Format("-I\"{0}\"", includePath.Replace('\\', '/')));
            }

            // Compile all C++ files
            var args = new List <string>();

            foreach (var sourceFile in sourceFiles)
            {
                var sourceFilename = Path.GetFileNameWithoutExtension(sourceFile);
                var task           = graph.Add <CompileCppTask>();

                // Use shared arguments
                args.Clear();
                args.AddRange(commonArgs);

                // Object File Name
                var objFile = Path.Combine(outputPath, sourceFilename + ".o");
                args.Add(string.Format("-o \"{0}\"", objFile.Replace('\\', '/')));
                output.ObjectFiles.Add(objFile);
                task.ProducedFiles.Add(objFile);

                // Source File Name
                args.Add("\"" + sourceFile.Replace('\\', '/') + "\"");

                // Request included files to exist
                var includes = IncludesCache.FindAllIncludedFiles(sourceFile);
                task.PrerequisiteFiles.AddRange(includes);

                // Compile
                task.WorkingDirectory = options.WorkingDirectory;
                task.CommandPath      = ClangPath;
                task.CommandArguments = string.Join(" ", args);
                task.PrerequisiteFiles.Add(sourceFile);
                task.InfoMessage = Path.GetFileName(sourceFile);
                task.Cost        = task.PrerequisiteFiles.Count; // TODO: include source file size estimation to improve tasks sorting
            }

            return(output);
        }
Example #7
0
        private static void BuildTargetBindings(RulesAssembly rules, TaskGraph graph, BuildData buildData)
        {
            var workspaceRoot    = buildData.TargetOptions.WorkingDirectory;
            var args             = new List <string>();
            var referencesToCopy = new HashSet <KeyValuePair <string, string> >();
            var buildOptions     = buildData.TargetOptions;

            foreach (var binaryModule in buildData.BinaryModules)
            {
                var binaryModuleName = binaryModule.Key;
                using (new ProfileEventScope(binaryModuleName))
                {
                    // TODO: add support for extending this code and support generating bindings projects for other scripting languages
                    var project = GetModuleProject(binaryModule.First(), buildData);

                    // Get source files
                    var sourceFiles = new List <string>();
                    foreach (var module in binaryModule)
                    {
                        sourceFiles.AddRange(buildData.Modules[module].SourceFiles.Where(x => x.EndsWith(".cs")));
                    }
                    sourceFiles.RemoveAll(x => x.EndsWith(BuildFilesPostfix));
                    var moduleGen = Path.Combine(project.ProjectFolderPath, "Source", binaryModuleName + ".Gen.cs");
                    if (!sourceFiles.Contains(moduleGen))
                    {
                        sourceFiles.Add(moduleGen);
                    }
                    sourceFiles.Sort();

                    // Setup build options
                    var buildPlatform       = Platform.BuildPlatform.Target;
                    var outputPath          = Path.GetDirectoryName(buildData.Target.GetOutputFilePath(buildOptions));
                    var outputFile          = Path.Combine(outputPath, binaryModuleName + ".CSharp.dll");
                    var outputDocFile       = Path.Combine(outputPath, binaryModuleName + ".CSharp.xml");
                    var monoRoot            = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Windows", "Mono");
                    var cscPath             = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
                    var exePath             = buildPlatform == TargetPlatform.Windows ? Path.Combine(monoRoot, "bin", "mono.exe") : "mono";
                    var referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api");
                    var references          = new HashSet <string>(buildOptions.ScriptingAPI.FileReferences);
                    foreach (var module in binaryModule)
                    {
                        if (!buildData.Modules.TryGetValue(module, out var moduleBuildOptions))
                        {
                            continue;
                        }

                        // Find references based on the modules dependencies
                        foreach (var dependencyName in moduleBuildOptions.PublicDependencies.Concat(moduleBuildOptions.PrivateDependencies))
                        {
                            var dependencyModule = buildData.Rules.GetModule(dependencyName);
                            if (dependencyModule != null &&
                                !string.IsNullOrEmpty(dependencyModule.BinaryModuleName) &&
                                dependencyModule.BinaryModuleName != binaryModuleName &&
                                buildData.Modules.TryGetValue(dependencyModule, out var dependencyModuleOptions))
                            {
                                foreach (var x in buildData.BinaryModules)
                                {
                                    if (x.Key == null || x.Key != dependencyModule.BinaryModuleName)
                                    {
                                        continue;
                                    }

                                    // Reference module output binary
                                    references.Add(Path.Combine(outputPath, dependencyModule.BinaryModuleName + ".CSharp.dll"));
                                }
                                foreach (var e in buildData.ReferenceBuilds)
                                {
                                    foreach (var q in e.Value.BuildInfo.BinaryModules)
                                    {
                                        if (q.Name == dependencyModule.BinaryModuleName && !string.IsNullOrEmpty(q.ManagedPath))
                                        {
                                            // Reference binary module build build for referenced target
                                            references.Add(q.ManagedPath);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // Setup C# compiler arguments
                    args.Clear();
                    args.Add("/nologo");
                    args.Add("/target:library");
                    args.Add("/platform:AnyCPU");
                    args.Add("/debug+");
                    args.Add("/debug:portable");
                    args.Add("/errorreport:prompt");
                    args.Add("/preferreduilang:en-US");
                    args.Add("/highentropyva+");
                    args.Add("/deterministic");
                    args.Add("/nostdlib+");
                    args.Add("/errorendlocation");
                    args.Add("/utf8output");
                    args.Add("/warn:4");
                    args.Add("/unsafe");
                    args.Add("/fullpaths");
                    args.Add("/langversion:7.3");
                    if (buildOptions.ScriptingAPI.IgnoreMissingDocumentationWarnings)
                    {
                        args.Add("-nowarn:1591");
                    }
                    args.Add(buildData.Configuration == TargetConfiguration.Debug ? "/optimize-" : "/optimize+");
                    args.Add(string.Format("/out:\"{0}\"", outputFile));
                    args.Add(string.Format("/doc:\"{0}\"", outputDocFile));
                    if (buildOptions.ScriptingAPI.Defines.Count != 0)
                    {
                        args.Add("/define:" + string.Join(";", buildOptions.ScriptingAPI.Defines));
                    }
                    if (buildData.Configuration == TargetConfiguration.Debug)
                    {
                        args.Add("/define:DEBUG");
                    }
                    args.Add(string.Format("/reference:\"{0}{1}mscorlib.dll\"", referenceAssemblies, Path.DirectorySeparatorChar));
                    foreach (var reference in buildOptions.ScriptingAPI.SystemReferences)
                    {
                        args.Add(string.Format("/reference:\"{0}{2}{1}.dll\"", referenceAssemblies, reference, Path.DirectorySeparatorChar));
                    }
                    foreach (var reference in references)
                    {
                        args.Add(string.Format("/reference:\"{0}\"", reference));
                    }
                    foreach (var sourceFile in sourceFiles)
                    {
                        args.Add("\"" + sourceFile + "\"");
                    }

                    // Generate response file with source files paths and compilation arguments
                    string responseFile = Path.Combine(buildOptions.IntermediateFolder, binaryModuleName + ".CSharp.response");
                    Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));

                    // Create C# compilation task
                    var task = graph.Add <Task>();
                    task.PrerequisiteFiles.Add(responseFile);
                    task.PrerequisiteFiles.AddRange(sourceFiles);
                    task.PrerequisiteFiles.AddRange(references);
                    task.ProducedFiles.Add(outputFile);
                    task.WorkingDirectory = workspaceRoot;
                    task.CommandPath      = exePath;
                    task.CommandArguments = $"\"{cscPath}\" /noconfig @\"{responseFile}\"";
                    task.InfoMessage      = "Compiling C# API for " + binaryModuleName;
                    task.Cost             = task.PrerequisiteFiles.Count;

                    // Copy referenced assemblies
                    foreach (var reference in buildOptions.ScriptingAPI.FileReferences)
                    {
                        var dstFile = Path.Combine(outputPath, Path.GetFileName(reference));
                        if (dstFile == reference)
                        {
                            continue;
                        }

                        referencesToCopy.Add(new KeyValuePair <string, string>(dstFile, reference));
                    }
                }
            }

            // Copy files (using hash set to prevent copying the same file twice when building multiple scripting modules using the same files)
            foreach (var e in referencesToCopy)
            {
                var dst = e.Key;
                var src = e.Value;
                graph.AddCopyFile(dst, src);

                var srcPdb = Path.ChangeExtension(src, "pdb");
                if (File.Exists(srcPdb))
                {
                    graph.AddCopyFile(Path.ChangeExtension(dst, "pdb"), srcPdb);
                }

                var srcXml = Path.ChangeExtension(src, "xml");
                if (File.Exists(srcXml))
                {
                    graph.AddCopyFile(Path.ChangeExtension(dst, "xml"), srcXml);
                }
            }
        }
Example #8
0
        /// <inheritdoc />
        public override void LinkFiles(TaskGraph graph, BuildOptions options, string outputFilePath)
        {
            var linkEnvironment = options.LinkEnv;
            var task            = graph.Add <LinkTask>();

            // Setup arguments
            var args = new List <string>();

            SetupLinkFilesArgs(graph, options, args);
            {
                // Suppress startup banner
                args.Add("/NOLOGO");

                // Report internal compiler errors
                args.Add("/ERRORREPORT:PROMPT");

                // Output File Name
                args.Add(string.Format("/OUT:\"{0}\"", outputFilePath));

                // Specify target platform
                switch (Architecture)
                {
                case TargetArchitecture.x86:
                    args.Add("/MACHINE:x86");
                    break;

                case TargetArchitecture.x64:
                    args.Add("/MACHINE:x64");
                    break;

                case TargetArchitecture.ARM:
                case TargetArchitecture.ARM64:
                    args.Add("/MACHINE:ARM");
                    break;

                default: throw new InvalidArchitectureException(Architecture);
                }

                // Specify subsystem
                args.Add("/SUBSYSTEM:WINDOWS");

                // Generate Windows Metadata
                if (linkEnvironment.GenerateWindowsMetadata)
                {
                    args.Add("/WINMD");
                    args.Add(string.Format("/WINMDFILE:\"{0}\"", Path.ChangeExtension(outputFilePath, "winmd")));
                    args.Add("/APPCONTAINER");
                    if (linkEnvironment.Output == LinkerOutput.SharedLibrary)
                    {
                        args.Add("/DYNAMICBASE");
                    }
                }

                if (linkEnvironment.LinkTimeCodeGeneration)
                {
                    // Link-time code generation
                    args.Add("/LTCG");
                }

                if (linkEnvironment.Output == LinkerOutput.ImportLibrary)
                {
                    // Create an import library
                    args.Add("/DEF");

                    // Ignore libraries
                    args.Add("/NODEFAULTLIB");

                    // Specify the name
                    args.Add(string.Format("/NAME:\"{0}\"", Path.GetFileNameWithoutExtension(outputFilePath)));

                    // Ignore warnings about files with no public symbols
                    args.Add("/IGNORE:4221");
                }
                else
                {
                    // Don't create Side-by-Side Assembly Manifest
                    args.Add("/MANIFEST:NO");

                    // Fixed Base Address
                    args.Add("/FIXED:NO");

                    if (Architecture == TargetArchitecture.x86)
                    {
                        // Handle Large Addresses
                        args.Add("/LARGEADDRESSAWARE");
                    }

                    // Compatible with Data Execution Prevention
                    args.Add("/NXCOMPAT");

                    // Allow delay-loaded DLLs to be explicitly unloaded
                    args.Add("/DELAY:UNLOAD");

                    if (linkEnvironment.Output == LinkerOutput.SharedLibrary)
                    {
                        // Build a DLL
                        args.Add("/DLL");
                    }

                    // Redirect imports LIB file auto-generated for EXE/DLL
                    var libFile = Path.ChangeExtension(outputFilePath, Platform.StaticLibraryFileExtension);
                    args.Add("/IMPLIB:\"" + libFile + "\"");
                    task.ProducedFiles.Add(libFile);

                    // Don't embed the full PDB path
                    args.Add("/PDBALTPATH:%_PDB%");

                    // Optimize
                    if (linkEnvironment.Optimization && !linkEnvironment.UseIncrementalLinking)
                    {
                        // Generate an EXE checksum
                        args.Add("/RELEASE");

                        // Eliminate unreferenced symbols
                        args.Add("/OPT:REF");

                        // Remove redundant COMDATs
                        args.Add("/OPT:ICF");
                    }
                    else
                    {
                        // Keep symbols that are unreferenced
                        args.Add("/OPT:NOREF");

                        // Disable identical COMDAT folding
                        args.Add("/OPT:NOICF");
                    }

                    // Link Incrementally
                    if (linkEnvironment.UseIncrementalLinking)
                    {
                        args.Add("/INCREMENTAL");
                    }
                    else
                    {
                        args.Add("/INCREMENTAL:NO");
                    }

                    if (linkEnvironment.DebugInformation)
                    {
                        // Generate debug information
                        if (Toolset != WindowsPlatformToolset.v140 && linkEnvironment.UseFastPDBLinking)
                        {
                            args.Add("/DEBUG:FASTLINK");
                        }
                        else if (linkEnvironment.UseFullDebugInformation)
                        {
                            args.Add("/DEBUG:FULL");
                        }
                        else
                        {
                            args.Add("/DEBUG");
                        }

                        // Use Program Database
                        var pdbFile = Path.ChangeExtension(outputFilePath, Platform.ProgramDatabaseFileExtension);
                        args.Add(string.Format("/PDB:\"{0}\"", pdbFile));
                        task.ProducedFiles.Add(pdbFile);
                    }
                }
            }

            // Delay-load DLLs
            if (linkEnvironment.Output == LinkerOutput.Executable || linkEnvironment.Output == LinkerOutput.SharedLibrary)
            {
                foreach (var dll in options.DelayLoadLibraries)
                {
                    args.Add(string.Format("/DELAYLOAD:\"{0}\"", dll));
                }
            }

            // Additional lib paths
            foreach (var libpath in linkEnvironment.LibraryPaths)
            {
                args.Add(string.Format("/LIBPATH:\"{0}\"", libpath));
            }

            // Input libraries
            task.PrerequisiteFiles.AddRange(linkEnvironment.InputLibraries);
            foreach (var library in linkEnvironment.InputLibraries)
            {
                args.Add(string.Format("\"{0}\"", library));
            }

            // Input files
            task.PrerequisiteFiles.AddRange(linkEnvironment.InputFiles);
            foreach (var file in linkEnvironment.InputFiles)
            {
                args.Add(string.Format("\"{0}\"", file));
            }

            // Use a response file (it can contain any commands that you would specify on the command line)
            bool   useResponseFile = true;
            string responseFile    = null;

            if (useResponseFile)
            {
                responseFile = Path.Combine(options.IntermediateFolder, Path.GetFileName(outputFilePath) + ".response");
                task.PrerequisiteFiles.Add(responseFile);
                Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));
            }

            // Link
            task.WorkingDirectory = options.WorkingDirectory;
            task.CommandPath      = linkEnvironment.Output == LinkerOutput.ImportLibrary ? _libToolPath : _linkerPath;
            task.CommandArguments = useResponseFile ? string.Format("@\"{0}\"", responseFile) : string.Join(" ", args);
            if (linkEnvironment.Output == LinkerOutput.ImportLibrary)
            {
                task.InfoMessage = "Building import library " + outputFilePath;
            }
            else
            {
                task.InfoMessage = "Linking " + outputFilePath;
            }
            task.Cost = task.PrerequisiteFiles.Count;
            task.ProducedFiles.Add(outputFilePath);

            // Check if need to generate documentation
            if (linkEnvironment.GenerateDocumentation)
            {
                args.Clear();
                var docTask = graph.Add <Task>();

                // Use old input format
                args.Add("/old");
                args.Add(string.Format("\"{0}\"", Path.GetFileNameWithoutExtension(outputFilePath)));

                // Suppress copyright message
                args.Add("/nologo");

                // Output file
                var outputDocFile = Path.ChangeExtension(outputFilePath, "xml");
                docTask.ProducedFiles.Add(outputDocFile);
                args.Add(string.Format("/Fo\"{0}\"", outputDocFile));

                // Input files
                docTask.PrerequisiteFiles.AddRange(linkEnvironment.DocumentationFiles);
                foreach (var file in linkEnvironment.DocumentationFiles)
                {
                    args.Add(string.Format("/Fs\"{0}\"", file));
                }

                // Generate docs
                docTask.WorkingDirectory = options.WorkingDirectory;
                docTask.CommandPath      = _xdcmakePath;
                docTask.CommandArguments = string.Join(" ", args);
                docTask.Cost             = linkEnvironment.DocumentationFiles.Count;
            }

            // Check if need to generate metadata file
            if (linkEnvironment.GenerateWindowsMetadata)
            {
                var configFile   = Path.Combine(options.IntermediateFolder, Path.GetFileNameWithoutExtension(outputFilePath) + ".priconfig.xml");
                var manifestFile = Path.Combine(options.IntermediateFolder, Path.GetFileNameWithoutExtension(outputFilePath) + ".AppxManifest.xml");
                var priFile      = Path.ChangeExtension(outputFilePath, "pri");

                // Generate pri config file
                var priConfigTask = graph.Add <Task>();
                priConfigTask.WorkingDirectory = options.WorkingDirectory;
                priConfigTask.CommandPath      = _makepriPath;
                priConfigTask.CommandArguments = string.Format("createconfig /cf \"{0}\" /dq en-US /o", configFile);
                priConfigTask.Cost             = 1;
                priConfigTask.ProducedFiles.Add(configFile);

                // Create AppxManifest file
                {
                    using (var stringWriter = new StringWriterWithEncoding(Encoding.UTF8))
                        using (var xmlTextWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings
                        {
                            Encoding = Encoding.UTF8,
                            Indent = true,
                        }))
                        {
                            xmlTextWriter.WriteStartDocument();

                            // Package
                            {
                                xmlTextWriter.WriteStartElement("Package", "http://schemas.microsoft.com/appx/2010/manifest");

                                // Identity
                                {
                                    xmlTextWriter.WriteStartElement("Identity");

                                    xmlTextWriter.WriteAttributeString("Name", "FlaxGame");
                                    xmlTextWriter.WriteAttributeString("Publisher", "CN=Flax, O=Flax, C=Poland");
                                    xmlTextWriter.WriteAttributeString("Version", "1.0.0.0"); // TODO: get Flax version number

                                    switch (Architecture)
                                    {
                                    case TargetArchitecture.AnyCPU:
                                        xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "neutral");
                                        break;

                                    case TargetArchitecture.x86:
                                        xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "x86");
                                        break;

                                    case TargetArchitecture.x64:
                                        xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "x64");
                                        break;

                                    case TargetArchitecture.ARM:
                                    case TargetArchitecture.ARM64:
                                        xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "arm");
                                        break;

                                    default: throw new InvalidArchitectureException(Architecture);
                                    }

                                    xmlTextWriter.WriteEndElement();
                                }

                                // Properties
                                {
                                    xmlTextWriter.WriteStartElement("Properties");

                                    // TODO: better logo handling
                                    var logoSrcPath = Path.Combine(Globals.EngineRoot, "Source", "Logo.png");
                                    var logoDstPath = Path.Combine(options.IntermediateFolder, "Logo.png");
                                    if (!File.Exists(logoDstPath))
                                    {
                                        Utilities.FileCopy(logoSrcPath, logoDstPath);
                                    }

                                    xmlTextWriter.WriteElementString("DisplayName", "FlaxGame");
                                    xmlTextWriter.WriteElementString("PublisherDisplayName", "Flax");
                                    xmlTextWriter.WriteElementString("Logo", "Logo.png");

                                    xmlTextWriter.WriteEndElement();
                                }

                                // Resources
                                {
                                    xmlTextWriter.WriteStartElement("Resources");

                                    xmlTextWriter.WriteStartElement("Resource");
                                    xmlTextWriter.WriteAttributeString("Language", "en-us");
                                    xmlTextWriter.WriteEndElement();

                                    xmlTextWriter.WriteEndElement();
                                }

                                // Prerequisites
                                {
                                    xmlTextWriter.WriteStartElement("Prerequisites");

                                    xmlTextWriter.WriteElementString("OSMinVersion", "6.2");
                                    xmlTextWriter.WriteElementString("OSMaxVersionTested", "6.2");

                                    xmlTextWriter.WriteEndElement();
                                }
                            }

                            xmlTextWriter.WriteEndDocument();
                            xmlTextWriter.Flush();

                            // Save manifest to file
                            var contents = stringWriter.GetStringBuilder().ToString();
                            Utilities.WriteFileIfChanged(manifestFile, contents);
                        }
                }

                var dummyWorkspace = Path.Combine(options.IntermediateFolder, "Dummy");
                if (!Directory.Exists(dummyWorkspace))
                {
                    Directory.CreateDirectory(dummyWorkspace);
                }

                // Generate pri file
                var priNewFile = graph.Add <Task>();
                priNewFile.WorkingDirectory = options.WorkingDirectory;
                priNewFile.CommandPath      = _makepriPath;
                priNewFile.CommandArguments = string.Format("new /cf \"{0}\" /pr \"{1}\" /of \"{2}\" /mn \"{3}\" /o", configFile, dummyWorkspace, priFile, manifestFile);
                priNewFile.Cost             = 1;
                priNewFile.PrerequisiteFiles.Add(configFile);
                priNewFile.ProducedFiles.Add(priFile);
            }
        }
Example #9
0
        /// <inheritdoc />
        public override CompileOutput CompileCppFiles(TaskGraph graph, BuildOptions options, List <string> sourceFiles, string outputPath)
        {
            var compileEnvironment = options.CompileEnv;
            var output             = new CompileOutput();

            // Setup arguments shared by all source files
            var commonArgs = new List <string>();

            SetupCompileCppFilesArgs(graph, options, commonArgs);
            {
                // Suppress Startup Banner
                commonArgs.Add("/nologo");

                // Compile Without Linking
                commonArgs.Add("/c");

                // Generate Intrinsic Functions
                if (compileEnvironment.IntrinsicFunctions)
                {
                    commonArgs.Add("/Oi");
                }

                // Enable Function-Level Linking
                if (compileEnvironment.FunctionLevelLinking)
                {
                    commonArgs.Add("/Gy");
                }
                else
                {
                    commonArgs.Add("/Gy-");
                }

                // List Include Files
                //commonArgs.Add("/showIncludes");

                // Code Analysis
                commonArgs.Add("/analyze-");

                // Remove unreferenced COMDAT
                commonArgs.Add("/Zc:inline");

                // Favor Small Code, Favor Fast Code
                if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.FastCode)
                {
                    commonArgs.Add("/Ot");
                }
                else if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.SmallCode)
                {
                    commonArgs.Add("/Os");
                }

                // Run-Time Error Checks
                if (compileEnvironment.RuntimeChecks && !compileEnvironment.CompileAsWinRT)
                {
                    commonArgs.Add("/RTC1");
                }

                // Enable Additional Security Checks
                if (compileEnvironment.RuntimeChecks)
                {
                    commonArgs.Add("/sdl");
                }

                // Inline Function Expansion
                if (compileEnvironment.Inlining)
                {
                    commonArgs.Add("/Ob2");
                }

                if (compileEnvironment.DebugInformation)
                {
                    // Debug Information Format
                    commonArgs.Add("/Zi");

                    // Enhance Optimized Debugging
                    commonArgs.Add("/Zo");
                }

                if (compileEnvironment.Optimization)
                {
                    // Enable Most Speed Optimizations
                    commonArgs.Add("/Ox");

                    // Generate Intrinsic Functions
                    commonArgs.Add("/Oi");

                    // Frame-Pointer Omission
                    commonArgs.Add("/Oy");

                    if (compileEnvironment.WholeProgramOptimization)
                    {
                        // Whole Program Optimization
                        commonArgs.Add("/GL");
                    }
                }
                else
                {
                    // Disable compiler optimizations (Debug)
                    commonArgs.Add("/Od");

                    // Frame-Pointer Omission
                    commonArgs.Add("/Oy-");
                }

                // Full Path of Source Code File in Diagnostics
                commonArgs.Add("/FC");

                // Report Internal Compiler Errors
                commonArgs.Add("/errorReport:prompt");

                // Exception Handling Model
                if (!compileEnvironment.CompileAsWinRT)
                {
                    if (compileEnvironment.EnableExceptions)
                    {
                        commonArgs.Add("/EHsc");
                    }
                    else
                    {
                        commonArgs.Add("/D_HAS_EXCEPTIONS=0");
                    }
                }

                // Eliminate Duplicate Strings
                if (compileEnvironment.StringPooling)
                {
                    commonArgs.Add("/GF");
                }
                else
                {
                    commonArgs.Add("/GF-");
                }

                // Use Run-Time Library
                if (compileEnvironment.UseDebugCRT)
                {
                    commonArgs.Add("/MDd");
                }
                else
                {
                    commonArgs.Add("/MD");
                }

                // Specify floating-point behavior
                commonArgs.Add("/fp:fast");
                commonArgs.Add("/fp:except-");

                // Buffer Security Check
                if (compileEnvironment.BufferSecurityCheck)
                {
                    commonArgs.Add("/GS");
                }
                else
                {
                    commonArgs.Add("/GS-");
                }

                // Enable Run-Time Type Information
                if (compileEnvironment.RuntimeTypeInfo)
                {
                    commonArgs.Add("/GR");
                }
                else
                {
                    commonArgs.Add("/GR-");
                }

                // Treats all compiler warnings as errors
                if (compileEnvironment.TreatWarningsAsErrors)
                {
                    commonArgs.Add("/WX");
                }
                else
                {
                    commonArgs.Add("/WX-");
                }

                // Show warnings
                // TODO: compile with W4 and fix all warnings
                commonArgs.Add("/W3");

                // Silence macro redefinition warning
                commonArgs.Add("/wd\"4005\"");

                // wchar_t is Native Type
                commonArgs.Add("/Zc:wchar_t");

                // Common Language Runtime Compilation
                if (compileEnvironment.CompileAsWinRT)
                {
                    commonArgs.Add("/clr");
                }

                // Windows Runtime Compilation
                if (compileEnvironment.WinRTComponentExtensions)
                {
                    commonArgs.Add("/ZW");
                    //commonArgs.Add("/ZW:nostdlib");

                    var dir = GetCppCXMetadataDirectory();
                    if (dir != null)
                    {
                        commonArgs.Add(string.Format("/AI\"{0}\"", dir));
                        commonArgs.Add(string.Format("/FU\"{0}\\platform.winmd\"", dir));
                    }
                }
            }

            // Add preprocessor definitions
            foreach (var definition in compileEnvironment.PreprocessorDefinitions)
            {
                commonArgs.Add(string.Format("/D \"{0}\"", definition));
            }

            // Add include paths
            foreach (var includePath in compileEnvironment.IncludePaths)
            {
                AddIncludePath(commonArgs, includePath);
            }

            // Compile all C++ files
            var args = new List <string>();

            foreach (var sourceFile in sourceFiles)
            {
                var sourceFilename = Path.GetFileNameWithoutExtension(sourceFile);
                var task           = graph.Add <CompileCppTask>();

                // Use shared arguments
                args.Clear();
                args.AddRange(commonArgs);

                if (compileEnvironment.DebugInformation)
                {
                    // Program Database File Name
                    var pdbFile = Path.Combine(outputPath, sourceFilename + ".pdb");
                    args.Add(string.Format("/Fd\"{0}\"", pdbFile));
                    output.DebugDataFiles.Add(pdbFile);
                }

                if (compileEnvironment.GenerateDocumentation)
                {
                    // Process Documentation Comments
                    var docFile = Path.Combine(outputPath, sourceFilename + ".xdc");
                    args.Add(string.Format("/doc\"{0}\"", docFile));
                    output.DocumentationFiles.Add(docFile);
                }

                // Object File Name
                var objFile = Path.Combine(outputPath, sourceFilename + ".obj");
                args.Add(string.Format("/Fo\"{0}\"", objFile));
                output.ObjectFiles.Add(objFile);
                task.ProducedFiles.Add(objFile);

                // Source File Name
                args.Add("\"" + sourceFile + "\"");

                // Request included files to exist
                var includes = IncludesCache.FindAllIncludedFiles(sourceFile);
                task.PrerequisiteFiles.AddRange(includes);

                // Compile
                task.WorkingDirectory = options.WorkingDirectory;
                task.CommandPath      = _compilerPath;
                task.CommandArguments = string.Join(" ", args);
                task.PrerequisiteFiles.Add(sourceFile);
                task.Cost = task.PrerequisiteFiles.Count; // TODO: include source file size estimation to improve tasks sorting
            }

            return(output);
        }
Example #10
0
        /// <inheritdoc />
        public override void LinkFiles(TaskGraph graph, BuildOptions options, string outputFilePath)
        {
            var linkEnvironment = options.LinkEnv;
            var task            = graph.Add <LinkTask>();
            var isArchive       = linkEnvironment.Output == LinkerOutput.StaticLibrary || linkEnvironment.Output == LinkerOutput.ImportLibrary;

            // Setup arguments
            var args = new List <string>();
            {
                args.Add(string.Format("-o \"{0}\"", outputFilePath));
                AddArgsCommon(options, args);

                if (isArchive)
                {
                    args.Add("-static");
                }
                else
                {
                    args.Add("-dead_strip");
                    args.Add("-rpath @executable_path/");
                    if (linkEnvironment.Output == LinkerOutput.SharedLibrary)
                    {
                        args.Add("-dynamiclib");
                    }
                }
            }

            // Input libraries
            var libraryPaths = new HashSet <string>();
            var dylibs       = new HashSet <string>();

            foreach (var library in linkEnvironment.InputLibraries)
            {
                var dir = Path.GetDirectoryName(library);
                var ext = Path.GetExtension(library);
                if (ext == ".framework")
                {
                    args.Add(string.Format("-framework {0}", library.Substring(0, library.Length - ext.Length)));
                }
                else if (string.IsNullOrEmpty(dir))
                {
                    args.Add(string.Format("\"-l{0}\"", library));
                }
                else if (string.IsNullOrEmpty(ext))
                {
                    // Skip executable
                }
                else if (ext == ".dylib")
                {
                    // Link against dynamic library
                    dylibs.Add(library);
                    task.PrerequisiteFiles.Add(library);
                    libraryPaths.Add(dir);
                    args.Add(string.Format("\"{0}\"", library));
                }
                else
                {
                    task.PrerequisiteFiles.Add(library);
                    args.Add(string.Format("\"{0}\"", GetLibName(library)));
                }
            }
            foreach (var library in options.Libraries)
            {
                var dir = Path.GetDirectoryName(library);
                var ext = Path.GetExtension(library);
                if (ext == ".framework")
                {
                    args.Add(string.Format("-framework {0}", library.Substring(0, library.Length - ext.Length)));
                }
                else if (string.IsNullOrEmpty(dir))
                {
                    args.Add(string.Format("\"-l{0}\"", library));
                }
                else if (string.IsNullOrEmpty(ext))
                {
                    // Skip executable
                }
                else if (ext == ".dylib")
                {
                    // Link against dynamic library
                    dylibs.Add(library);
                    task.PrerequisiteFiles.Add(library);
                    libraryPaths.Add(dir);
                    args.Add(string.Format("\"{0}\"", library));
                }
                else
                {
                    task.PrerequisiteFiles.Add(library);
                    args.Add(string.Format("\"{0}\"", GetLibName(library)));
                }
            }

            // Input files
            task.PrerequisiteFiles.AddRange(linkEnvironment.InputFiles);
            foreach (var file in linkEnvironment.InputFiles)
            {
                var ext = Path.GetExtension(file);
                if (ext == ".framework")
                {
                    args.Add(string.Format("-framework {0}", file.Substring(0, file.Length - ext.Length)));
                }
                else
                {
                    args.Add(string.Format("\"{0}\"", file.Replace('\\', '/')));
                }
            }

            // Additional lib paths
            libraryPaths.AddRange(linkEnvironment.LibraryPaths);
            foreach (var path in libraryPaths)
            {
                args.Add(string.Format("-L\"{0}\"", path.Replace('\\', '/')));
            }

            // Use a response file (it can contain any commands that you would specify on the command line)
            bool   useResponseFile = true;
            string responseFile    = null;

            if (useResponseFile)
            {
                responseFile = Path.Combine(options.IntermediateFolder, Path.GetFileName(outputFilePath) + ".response");
                task.PrerequisiteFiles.Add(responseFile);
                Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));
            }

            // Link
            task.WorkingDirectory = options.WorkingDirectory;
            task.CommandPath      = isArchive ? ArchiverPath : LinkerPath;
            task.CommandArguments = useResponseFile ? string.Format("@\"{0}\"", responseFile) : string.Join(" ", args);
            task.InfoMessage      = "Linking " + outputFilePath;
            task.Cost             = task.PrerequisiteFiles.Count;
            task.ProducedFiles.Add(outputFilePath);

            Task lastTask = task;

            if (options.LinkEnv.Output == LinkerOutput.Executable)
            {
                // Fix rpath for dynamic libraries
                foreach (var library in dylibs)
                {
                    var rpathTask = graph.Add <Task>();
                    rpathTask.ProducedFiles.Add(outputFilePath);
                    rpathTask.WorkingDirectory = options.WorkingDirectory;
                    rpathTask.CommandPath      = "install_name_tool";
                    var filename     = Path.GetFileName(library);
                    var outputFolder = Path.GetDirectoryName(outputFilePath);
                    rpathTask.CommandArguments = string.Format("-change \"{0}/{1}\" \"@loader_path/{1}\" {2}", outputFolder, filename, outputFilePath);
                    rpathTask.InfoMessage      = "Fixing rpath to " + filename;
                    rpathTask.Cost             = 1;
                    rpathTask.DisableCache     = true;
                    rpathTask.DependentTasks   = new HashSet <Task>();
                    rpathTask.DependentTasks.Add(lastTask);
                    lastTask = rpathTask;
                }
            }
            if (!options.LinkEnv.DebugInformation)
            {
                // Strip debug symbols
                var stripTask = graph.Add <Task>();
                stripTask.ProducedFiles.Add(outputFilePath);
                stripTask.WorkingDirectory = options.WorkingDirectory;
                stripTask.CommandPath      = "strip";
                stripTask.CommandArguments = string.Format("\"{0}\" -S", outputFilePath);
                stripTask.InfoMessage      = "Striping " + outputFilePath;
                stripTask.Cost             = 1;
                stripTask.DisableCache     = true;
                stripTask.DependentTasks   = new HashSet <Task>();
                stripTask.DependentTasks.Add(lastTask);
            }
        }
Example #11
0
        /// <inheritdoc />
        public override CompileOutput CompileCppFiles(TaskGraph graph, BuildOptions options, List <string> sourceFiles, string outputPath)
        {
            var compileEnvironment = options.CompileEnv;
            var output             = new CompileOutput();

            // Setup arguments shared by all source files
            var commonArgs = new List <string>();

            {
                commonArgs.Add("-c");
                commonArgs.Add("-fmessage-length=0");
                commonArgs.Add("-pipe");
                commonArgs.Add("-x");
                commonArgs.Add("objective-c++");
                commonArgs.Add("-std=c++14");
                commonArgs.Add("-stdlib=libc++");
                AddArgsCommon(options, commonArgs);

                switch (Architecture)
                {
                case TargetArchitecture.x64:
                    commonArgs.Add("-msse2");
                    break;
                }

                commonArgs.Add("-Wdelete-non-virtual-dtor");
                commonArgs.Add("-fno-math-errno");
                commonArgs.Add("-fasm-blocks");
                commonArgs.Add("-fpascal-strings");
                commonArgs.Add("-fdiagnostics-format=msvc");

                commonArgs.Add("-Wno-absolute-value");
                commonArgs.Add("-Wno-nullability-completeness");
                commonArgs.Add("-Wno-undef-prefix");
                commonArgs.Add("-Wno-expansion-to-defined");
                commonArgs.Add("-Wno-non-virtual-dtor");

                // Hide all symbols by default
                commonArgs.Add("-fvisibility-inlines-hidden");
                commonArgs.Add("-fvisibility-ms-compat");

                if (compileEnvironment.RuntimeTypeInfo)
                {
                    commonArgs.Add("-frtti");
                }
                else
                {
                    commonArgs.Add("-fno-rtti");
                }

                if (compileEnvironment.TreatWarningsAsErrors)
                {
                    commonArgs.Add("-Wall -Werror");
                }

                // TODO: compileEnvironment.IntrinsicFunctions
                // TODO: compileEnvironment.FunctionLevelLinking
                // TODO: compileEnvironment.FavorSizeOrSpeed
                // TODO: compileEnvironment.RuntimeChecks
                // TODO: compileEnvironment.StringPooling
                // TODO: compileEnvironment.BufferSecurityCheck

                if (compileEnvironment.DebugInformation)
                {
                    commonArgs.Add("-gdwarf-2");
                }

                commonArgs.Add("-pthread");

                if (compileEnvironment.Optimization)
                {
                    commonArgs.Add("-O3");
                }
                else
                {
                    commonArgs.Add("-O0");
                }

                if (!compileEnvironment.Inlining)
                {
                    commonArgs.Add("-fno-inline-functions");
                    commonArgs.Add("-fno-inline");
                }

                if (compileEnvironment.EnableExceptions)
                {
                    commonArgs.Add("-fexceptions");
                }
                else
                {
                    commonArgs.Add("-fno-exceptions");
                }
            }

            // Add preprocessor definitions
            foreach (var definition in compileEnvironment.PreprocessorDefinitions)
            {
                commonArgs.Add(string.Format("-D \"{0}\"", definition));
            }

            // Add include paths
            foreach (var includePath in compileEnvironment.IncludePaths)
            {
                commonArgs.Add(string.Format("-I\"{0}\"", includePath.Replace('\\', '/')));
            }

            // Compile all C++ files
            var args = new List <string>();

            foreach (var sourceFile in sourceFiles)
            {
                var sourceFilename = Path.GetFileNameWithoutExtension(sourceFile);
                var task           = graph.Add <CompileCppTask>();

                // Use shared arguments
                args.Clear();
                args.AddRange(commonArgs);

                // Object File Name
                var objFile = Path.Combine(outputPath, sourceFilename + ".o");
                args.Add(string.Format("-o \"{0}\"", objFile.Replace('\\', '/')));
                output.ObjectFiles.Add(objFile);
                task.ProducedFiles.Add(objFile);

                // Source File Name
                args.Add("\"" + sourceFile.Replace('\\', '/') + "\"");

                // Request included files to exist
                var includes = IncludesCache.FindAllIncludedFiles(sourceFile);
                task.PrerequisiteFiles.AddRange(includes);

                // Compile
                task.WorkingDirectory = options.WorkingDirectory;
                task.CommandPath      = ClangPath;
                task.CommandArguments = string.Join(" ", args);
                task.PrerequisiteFiles.Add(sourceFile);
                task.InfoMessage = Path.GetFileName(sourceFile);
                task.Cost        = task.PrerequisiteFiles.Count; // TODO: include source file size estimation to improve tasks sorting
            }

            return(output);
        }
Example #12
0
        private static void BuildDotNet(TaskGraph graph, BuildData buildData, NativeCpp.BuildOptions buildOptions, string name, List <string> sourceFiles, HashSet <string> fileReferences = null)
        {
            // Setup build options
            var    buildPlatform = Platform.BuildTargetPlatform;
            var    outputPath = Path.GetDirectoryName(buildData.Target.GetOutputFilePath(buildOptions));
            var    outputFile = Path.Combine(outputPath, name + ".dll");
            var    outputDocFile = Path.Combine(outputPath, name + ".xml");
            string monoRoot, monoPath, cscPath;

            switch (buildPlatform)
            {
            case TargetPlatform.Windows:
            {
                monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Windows", "Mono");

                // Prefer installed Roslyn C# compiler over Mono one
                monoPath = null;
                cscPath  = Path.Combine(Path.GetDirectoryName(VCEnvironment.MSBuildPath), "Roslyn", "csc.exe");

                if (!File.Exists(cscPath))
                {
                    // Fallback to Mono binaries
                    monoPath = Path.Combine(monoRoot, "bin", "mono.exe");
                    cscPath  = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
                }
                break;
            }

            case TargetPlatform.Linux:
                monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Linux", "Mono");
                monoPath = Path.Combine(monoRoot, "bin", "mono");
                cscPath  = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
                break;

            case TargetPlatform.Mac:
                monoRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Editor", "Mac", "Mono");
                monoPath = Path.Combine(monoRoot, "bin", "mono");
                cscPath  = Path.Combine(monoRoot, "lib", "mono", "4.5", "csc.exe");
                break;

            default: throw new InvalidPlatformException(buildPlatform);
            }
            var referenceAssemblies = Path.Combine(monoRoot, "lib", "mono", "4.5-api");

            if (fileReferences == null)
            {
                fileReferences = buildOptions.ScriptingAPI.FileReferences;
            }
            else
            {
                fileReferences.AddRange(buildOptions.ScriptingAPI.FileReferences);
            }

            // Setup C# compiler arguments
            var args = new List <string>();

            args.Clear();
            args.Add("/nologo");
            args.Add("/target:library");
            args.Add("/platform:AnyCPU");
            args.Add("/debug+");
            args.Add("/debug:portable");
            args.Add("/errorreport:prompt");
            args.Add("/preferreduilang:en-US");
            args.Add("/highentropyva+");
            args.Add("/deterministic");
            args.Add("/nostdlib+");
            args.Add("/errorendlocation");
            args.Add("/utf8output");
            args.Add("/warn:4");
            args.Add("/unsafe");
            args.Add("/fullpaths");
            args.Add("/langversion:7.3");
            if (buildOptions.ScriptingAPI.IgnoreMissingDocumentationWarnings)
            {
                args.Add("-nowarn:1591");
            }
            args.Add(buildData.Configuration == TargetConfiguration.Debug ? "/optimize-" : "/optimize+");
            args.Add(string.Format("/out:\"{0}\"", outputFile));
            args.Add(string.Format("/doc:\"{0}\"", outputDocFile));
            if (buildOptions.ScriptingAPI.Defines.Count != 0)
            {
                args.Add("/define:" + string.Join(";", buildOptions.ScriptingAPI.Defines));
            }
            if (buildData.Configuration == TargetConfiguration.Debug)
            {
                args.Add("/define:DEBUG");
            }
            args.Add(string.Format("/reference:\"{0}{1}mscorlib.dll\"", referenceAssemblies, Path.DirectorySeparatorChar));
            foreach (var reference in buildOptions.ScriptingAPI.SystemReferences)
            {
                args.Add(string.Format("/reference:\"{0}{2}{1}.dll\"", referenceAssemblies, reference, Path.DirectorySeparatorChar));
            }
            foreach (var reference in fileReferences)
            {
                args.Add(string.Format("/reference:\"{0}\"", reference));
            }
            foreach (var sourceFile in sourceFiles)
            {
                args.Add("\"" + sourceFile + "\"");
            }

            // Generate response file with source files paths and compilation arguments
            string responseFile = Path.Combine(buildOptions.IntermediateFolder, name + ".response");

            Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));

            // Create C# compilation task
            var task = graph.Add <Task>();

            task.PrerequisiteFiles.Add(responseFile);
            task.PrerequisiteFiles.AddRange(sourceFiles);
            task.PrerequisiteFiles.AddRange(fileReferences);
            task.ProducedFiles.Add(outputFile);
            task.WorkingDirectory = buildData.TargetOptions.WorkingDirectory;
            task.InfoMessage      = "Compiling " + outputFile;
            task.Cost             = task.PrerequisiteFiles.Count;

            if (monoPath != null)
            {
                task.CommandPath      = monoPath;
                task.CommandArguments = $"\"{cscPath}\" /noconfig @\"{responseFile}\"";
            }
            else
            {
                // The "/shared" flag enables the compiler server support:
                // https://github.com/dotnet/roslyn/blob/main/docs/compilers/Compiler%20Server.md

                task.CommandPath      = cscPath;
                task.CommandArguments = $"/noconfig /shared @\"{responseFile}\"";
            }

            // Copy referenced assemblies
            foreach (var srcFile in buildOptions.ScriptingAPI.FileReferences)
            {
                var dstFile = Path.Combine(outputPath, Path.GetFileName(srcFile));
                if (dstFile == srcFile || graph.HasCopyTask(dstFile, srcFile))
                {
                    continue;
                }
                graph.AddCopyFile(dstFile, srcFile);

                var srcPdb = Path.ChangeExtension(srcFile, "pdb");
                if (File.Exists(srcPdb))
                {
                    graph.AddCopyFile(Path.ChangeExtension(dstFile, "pdb"), srcPdb);
                }

                var srcXml = Path.ChangeExtension(srcFile, "xml");
                if (File.Exists(srcXml))
                {
                    graph.AddCopyFile(Path.ChangeExtension(dstFile, "xml"), srcXml);
                }
            }
        }
Example #13
0
        private static void BuildTargetDotNet(RulesAssembly rules, TaskGraph graph, Target target, Platform platform, TargetConfiguration configuration)
        {
            // Check if use custom project file
            if (!string.IsNullOrEmpty(target.CustomExternalProjectFilePath))
            {
                // Use msbuild to compile it
                var task = graph.Add <Task>();
                task.WorkingDirectory = Globals.Root;
                task.InfoMessage      = "Building " + Path.GetFileName(target.CustomExternalProjectFilePath);
                task.Cost             = 100;
                task.DisableCache     = true;
                task.CommandPath      = VCEnvironment.MSBuildPath;
                task.CommandArguments = string.Format("\"{0}\" /m /t:Build /p:Configuration=\"{1}\" /p:Platform=\"{2}\" {3} /nologo", target.CustomExternalProjectFilePath, configuration.ToString(), "AnyCPU", VCEnvironment.Verbosity);
                return;
            }

            // Warn if target has no valid modules
            if (target.Modules.Count == 0)
            {
                Log.Warning(string.Format("Target {0} has no modules to build", target.Name));
            }

            // Pick a project
            var project = Globals.Project;

            if (target is ProjectTarget projectTarget)
            {
                project = projectTarget.Project;
            }
            if (project == null)
            {
                throw new Exception($"Cannot build target {target.Name}. The project file is missing (.flaxproj located in the folder above).");
            }

            // Setup build environment for the target
            var targetBuildOptions = GetBuildOptions(target, platform, null, TargetArchitecture.AnyCPU, configuration, project.ProjectFolderPath);

            using (new ProfileEventScope("PreBuild"))
            {
                // Pre build
                target.PreBuild(graph, targetBuildOptions);
                PreBuild?.Invoke(graph, targetBuildOptions);

                // Ensure that target build directories exist
                if (!target.IsPreBuilt && !Directory.Exists(targetBuildOptions.IntermediateFolder))
                {
                    Directory.CreateDirectory(targetBuildOptions.IntermediateFolder);
                }
                if (!target.IsPreBuilt && !Directory.Exists(targetBuildOptions.OutputFolder))
                {
                    Directory.CreateDirectory(targetBuildOptions.OutputFolder);
                }
            }

            // Setup building common data container
            var buildData = new BuildData
            {
                Project       = project,
                Graph         = graph,
                Rules         = rules,
                Target        = target,
                TargetOptions = targetBuildOptions,
                Platform      = platform,
                Architecture  = TargetArchitecture.AnyCPU,
                Configuration = configuration,
            };

            // Collect all modules
            using (new ProfileEventScope("CollectModules"))
            {
                foreach (var moduleName in target.Modules)
                {
                    var module = rules.GetModule(moduleName);
                    if (module != null)
                    {
                        CollectModules(buildData, module, true);
                    }
                    else
                    {
                        Log.Warning(string.Format("Missing module {0} (or invalid name specified)", moduleName));
                    }
                }
            }

            // Build all modules from target binary modules but in order of collecting (from independent to more dependant ones)
            var sourceFiles = new List <string>();

            using (new ProfileEventScope("BuildModules"))
            {
                foreach (var module in buildData.ModulesOrderList)
                {
                    if (buildData.BinaryModules.Any(x => x.Contains(module)))
                    {
                        var moduleOptions = BuildModule(buildData, module);

                        // Get source files
                        sourceFiles.AddRange(moduleOptions.SourceFiles.Where(x => x.EndsWith(".cs")));

                        // Merge module into target environment
                        foreach (var e in moduleOptions.OutputFiles)
                        {
                            buildData.TargetOptions.LinkEnv.InputFiles.Add(e);
                        }
                        foreach (var e in moduleOptions.DependencyFiles)
                        {
                            buildData.TargetOptions.DependencyFiles.Add(e);
                        }
                        foreach (var e in moduleOptions.OptionalDependencyFiles)
                        {
                            buildData.TargetOptions.OptionalDependencyFiles.Add(e);
                        }
                        buildData.TargetOptions.Libraries.AddRange(moduleOptions.Libraries);
                        buildData.TargetOptions.DelayLoadLibraries.AddRange(moduleOptions.DelayLoadLibraries);
                        buildData.TargetOptions.ScriptingAPI.Add(moduleOptions.ScriptingAPI);
                    }
                }
            }

            // Build
            var outputTargetFilePath = target.GetOutputFilePath(targetBuildOptions);
            var outputPath           = Path.GetDirectoryName(outputTargetFilePath);

            using (new ProfileEventScope("Build"))
            {
                // Cleanup source files
                sourceFiles.RemoveAll(x => x.EndsWith(BuildFilesPostfix));
                sourceFiles.Sort();

                // Build assembly
                BuildDotNet(graph, buildData, targetBuildOptions, target.OutputName, sourceFiles);
            }

            // Deploy files
            if (!target.IsPreBuilt)
            {
                using (new ProfileEventScope("DeployFiles"))
                {
                    foreach (var srcFile in targetBuildOptions.OptionalDependencyFiles.Where(File.Exists).Union(targetBuildOptions.DependencyFiles))
                    {
                        var dstFile = Path.Combine(outputPath, Path.GetFileName(srcFile));
                        graph.AddCopyFile(dstFile, srcFile);
                    }
                }
            }

            using (new ProfileEventScope("PostBuild"))
            {
                // Post build
                PostBuild?.Invoke(graph, targetBuildOptions);
                target.PostBuild(graph, targetBuildOptions);
            }
        }