Ejemplo n.º 1
0
        /**
         * Initializes environment variables required by toolchain. Different for 32 and 64 bit.
         */
        static void InitializeEnvironmentVariables(CPPTargetPlatform Platform)
        {
            if (!bAreEnvironmentVariablesAlreadyInitialized)
            {
                string VCVarsBatchFile = "";

                // Grab path to Visual Studio binaries from the system environment
                string BaseVSToolPath = WindowsPlatform.GetVSComnToolsPath(WindowsCompiler.VisualStudio2012);
                if (string.IsNullOrEmpty(BaseVSToolPath))
                {
                    BaseVSToolPath = "C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/Tools/";
                    if (Directory.Exists("C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/Tools/") == false)
                    {
                        throw new BuildException("Visual Studio 2012 must be installed in order to build this target.");
                    }
                }

                // 64 bit tool chain.
                if (Platform == CPPTargetPlatform.WinRT_ARM)
                {
                    VCVarsBatchFile = Path.Combine(BaseVSToolPath, "../../VC/bin/x86_arm/vcvarsx86_arm.bat");
                }
                else
                {
                    VCVarsBatchFile = Path.Combine(BaseVSToolPath, "../../VC/bin/x86_amd64/vcvarsx86_amd64.bat");
                }

                // @todo: This is failing when building the Win32 target through NMake!!!!
                Utils.SetEnvironmentVariablesFromBatchFile(VCVarsBatchFile);

                if (WinRTPlatform.ShouldCompileWinRT() == true)
                {
                    string EnvVarName = Utils.ResolveEnvironmentVariable(WindowsSDKDir + "Windows Metadata" + ";%LIBPATH%");
                    Environment.SetEnvironmentVariable("LIBPATH", EnvVarName);
                }

                bAreEnvironmentVariablesAlreadyInitialized = true;
            }
        }
Ejemplo n.º 2
0
        static string GetCLArguments_CPP(CPPEnvironment CompileEnvironment)
        {
            string Result = "";

            // Explicitly compile the file as C++.
            Result += " /TP";

            // C++/CLI requires that RTTI is left enabled
            if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLRDisabled)
            {
                if (CompileEnvironment.Config.bUseRTTI)
                {
                    // Enable C++ RTTI.
                    Result += " /GR";
                }
                else
                {
                    // Disable C++ RTTI.
                    Result += " /GR-";
                }
            }

            if (WinRTPlatform.ShouldCompileWinRT() == true)
            {
                // WinRT headers generate too many warnings for /W4
                Result += " /W1";
            }
            else
            {
                // Level 3 warnings.
//				Result += " /W3";
                Result += " /W1";
            }

            return(Result);
        }
Ejemplo n.º 3
0
        public override CPPOutput CompileCPPFiles(UEBuildTarget Target, CPPEnvironment CompileEnvironment, List <FileItem> SourceFiles, string ModuleName)
        {
            string Arguments = GetCLArguments_Global(CompileEnvironment);

            // Add include paths to the argument list.
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.IncludePaths)
            {
                Arguments += string.Format(" /I \"{0}\"", IncludePath);
            }
            foreach (string IncludePath in CompileEnvironment.Config.CPPIncludeInfo.SystemIncludePaths)
            {
                Arguments += string.Format(" /I \"{0}\"", IncludePath);
            }

            if ((CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled) ||
                (WinRTPlatform.ShouldCompileWinRT() == true))
            {
                // Add .NET framework assembly paths.  This is needed so that C++/CLI projects
                // can reference assemblies with #using, without having to hard code a path in the
                // .cpp file to the assembly's location.
                foreach (string AssemblyPath in CompileEnvironment.Config.SystemDotNetAssemblyPaths)
                {
                    Arguments += string.Format(" /AI \"{0}\"", AssemblyPath);
                }

                // Add explicit .NET framework assembly references
                foreach (string AssemblyName in CompileEnvironment.Config.FrameworkAssemblyDependencies)
                {
                    Arguments += string.Format(" /FU \"{0}\"", AssemblyName);
                }

                // Add private assembly references
                foreach (PrivateAssemblyInfo CurAssemblyInfo in CompileEnvironment.PrivateAssemblyDependencies)
                {
                    Arguments += string.Format(" /FU \"{0}\"", CurAssemblyInfo.FileItem.AbsolutePath);
                }
            }
            else
            {
                foreach (string AssemblyPath in CompileEnvironment.Config.SystemDotNetAssemblyPaths)
                {
                    Arguments += string.Format(" /AI \"{0}\"", AssemblyPath);
                }

                // Add explicit .NET framework assembly references
                foreach (string AssemblyName in CompileEnvironment.Config.FrameworkAssemblyDependencies)
                {
                    Arguments += string.Format(" /FU \"{0}\"", AssemblyName);
                }
            }

            // Add preprocessor definitions to the argument list.
            foreach (string Definition in CompileEnvironment.Config.Definitions)
            {
                Arguments += string.Format(" /D \"{0}\"", Definition);
            }

// Log.TraceInformation("Compile Arguments for {0}:", ModuleName);
// Log.TraceInformation(Arguments);

            var BuildPlatform = UEBuildPlatform.GetBuildPlatformForCPPTargetPlatform(CompileEnvironment.Config.Target.Platform);

            // Create a compile action for each source file.
            CPPOutput Result = new CPPOutput();

            foreach (FileItem SourceFile in SourceFiles)
            {
                Action CompileAction = new Action(ActionType.Compile);
                string FileArguments = "";
                bool   bIsPlainCFile = Path.GetExtension(SourceFile.AbsolutePath).ToUpperInvariant() == ".C";

                // Add the C++ source file and its included files to the prerequisite item list.
                AddPrerequisiteSourceFile(Target, BuildPlatform, CompileEnvironment, SourceFile, CompileAction.PrerequisiteItems);

                // If this is a CLR file then make sure our dependent assemblies are added as prerequisites
                if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled)
                {
                    foreach (PrivateAssemblyInfo CurPrivateAssemblyDependency in CompileEnvironment.PrivateAssemblyDependencies)
                    {
                        CompileAction.PrerequisiteItems.Add(CurPrivateAssemblyDependency.FileItem);
                    }
                }

                if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create)
                {
                    // Generate a CPP File that just includes the precompiled header.
                    string   PCHCPPFilename = "PCH." + Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename) + ".cpp";
                    string   PCHCPPPath     = Path.Combine(CompileEnvironment.Config.OutputDirectory, PCHCPPFilename);
                    FileItem PCHCPPFile     = FileItem.CreateIntermediateTextFile(
                        PCHCPPPath,
                        string.Format("#include \"{0}\"\r\n", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename)
                        );

                    // Make sure the original source directory the PCH header file existed in is added as an include
                    // path -- it might be a private PCH header and we need to make sure that its found!
                    string OriginalPCHHeaderDirectory = Path.GetDirectoryName(SourceFile.AbsolutePath);
                    FileArguments += string.Format(" /I \"{0}\"", OriginalPCHHeaderDirectory);

                    var PCHExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.WinRT].GetBinaryExtension(UEBuildBinaryType.PrecompiledHeader);

                    // Add the precompiled header file to the produced items list.
                    FileItem PrecompiledHeaderFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            Path.GetFileName(SourceFile.AbsolutePath) + PCHExtension
                            )
                        );
                    CompileAction.ProducedItems.Add(PrecompiledHeaderFile);
                    Result.PrecompiledHeaderFile = PrecompiledHeaderFile;

                    // Add the parameters needed to compile the precompiled header file to the command-line.
                    FileArguments += string.Format(" /Yc\"{0}\"", CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                    FileArguments += string.Format(" /Fp\"{0}\"", PrecompiledHeaderFile.AbsolutePath);
                    FileArguments += string.Format(" \"{0}\"", PCHCPPFile.AbsolutePath);

                    // If we're creating a PCH that will be used to compile source files for a library, we need
                    // the compiled modules to retain a reference to PCH's module, so that debugging information
                    // will be included in the library.  This is also required to avoid linker warning "LNK4206"
                    // when linking an application that uses this library.
                    if (CompileEnvironment.Config.bIsBuildingLibrary)
                    {
                        // NOTE: The symbol name we use here is arbitrary, and all that matters is that it is
                        // unique per PCH module used in our library
                        string FakeUniquePCHSymbolName = Path.GetFileNameWithoutExtension(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                        FileArguments += string.Format(" /Yl{0}", FakeUniquePCHSymbolName);
                    }
                    CompileAction.StatusDescription = PCHCPPFilename;
                }
                else
                {
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        CompileAction.bIsUsingPCH = true;
                        CompileAction.PrerequisiteItems.Add(CompileEnvironment.PrecompiledHeaderFile);
                        FileArguments += string.Format(" /Yu\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                        FileArguments += string.Format(" /Fp\"{0}\"", CompileEnvironment.PrecompiledHeaderFile.AbsolutePath);

                        // Is it unsafe to always force inclusion?  Clang is doing it, and .generated.cpp files
                        // won't work otherwise, because they're not located in the context of the module,
                        // so they can't access the module's PCH without an absolute path.
                        //if (CompileEnvironment.Config.bForceIncludePrecompiledHeader)
                        {
                            // Force include the precompiled header file.  This is needed because we may have selected a
                            // precompiled header that is different than the first direct include in the C++ source file, but
                            // we still need to make sure that our precompiled header is the first thing included!
                            FileArguments += string.Format(" /FI\"{0}\"", CompileEnvironment.Config.PCHHeaderNameInCode);
                        }
                    }

                    // Add the source file path to the command-line.
                    FileArguments += string.Format(" \"{0}\"", SourceFile.AbsolutePath);

                    CompileAction.StatusDescription = Path.GetFileName(SourceFile.AbsolutePath);
                }

                var ObjectFileExtension = UEBuildPlatform.BuildPlatformDictionary[UnrealTargetPlatform.WinRT].GetBinaryExtension(UEBuildBinaryType.Object);

                // Add the object file to the produced item list.
                FileItem ObjectFile = FileItem.GetItemByPath(
                    Path.Combine(
                        CompileEnvironment.Config.OutputDirectory,
                        Path.GetFileName(SourceFile.AbsolutePath) + ObjectFileExtension
                        )
                    );
                CompileAction.ProducedItems.Add(ObjectFile);
                Result.ObjectFiles.Add(ObjectFile);
                FileArguments += string.Format(" /Fo\"{0}\"", ObjectFile.AbsolutePath);

                // create PDBs per-file when not using debug info, otherwise it will try to share a PDB file, which causes
                // PCH creation to be serial rather than parallel (when debug info is disabled)
                // See https://udn.epicgames.com/lists/showpost.php?id=50619&list=unprog3
                if (!CompileEnvironment.Config.bCreateDebugInfo || BuildConfiguration.bUsePDBFiles)
                {
                    string PDBFileName;
                    bool   bActionProducesPDB = false;

                    // All files using the same PCH are required to share a PDB.
                    if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Include)
                    {
                        PDBFileName = Path.GetFileName(CompileEnvironment.Config.PrecompiledHeaderIncludeFilename);
                    }
                    // Files creating a PCH or ungrouped C++ files use a PDB per file.
                    else if (CompileEnvironment.Config.PrecompiledHeaderAction == PrecompiledHeaderAction.Create || !bIsPlainCFile)
                    {
                        PDBFileName        = Path.GetFileName(SourceFile.AbsolutePath);
                        bActionProducesPDB = true;
                    }
                    // Group all plain C files that doesn't use PCH into the same PDB
                    else
                    {
                        PDBFileName = "MiscPlainC";
                    }

                    // Specify the PDB file that the compiler should write to.
                    FileItem PDBFile = FileItem.GetItemByPath(
                        Path.Combine(
                            CompileEnvironment.Config.OutputDirectory,
                            PDBFileName + ".pdb"
                            )
                        );
                    FileArguments += string.Format(" /Fd\"{0}\"", PDBFile.AbsolutePath);

                    // Only use the PDB as an output file if we want PDBs and this particular action is
                    // the one that produces the PDB (as opposed to no debug info, where the above code
                    // is needed, but not the output PDB, or when multiple files share a single PDB, so
                    // only the action that generates it should count it as output directly)
                    if (BuildConfiguration.bUsePDBFiles && bActionProducesPDB)
                    {
                        CompileAction.ProducedItems.Add(PDBFile);
                        Result.DebugDataFiles.Add(PDBFile);
                    }
                }

                // Add C or C++ specific compiler arguments.
                if (bIsPlainCFile)
                {
                    FileArguments += GetCLArguments_C();
                }
                else
                {
                    FileArguments += GetCLArguments_CPP(CompileEnvironment);
                }

                CompileAction.WorkingDirectory  = Path.GetFullPath(".");
                CompileAction.CommandPath       = GetVCToolPath(CompileEnvironment.Config.Target.Platform, CompileEnvironment.Config.Target.Configuration, "cl");
                CompileAction.CommandArguments  = Arguments + FileArguments + CompileEnvironment.Config.AdditionalArguments;
                CompileAction.StatusDescription = string.Format("{0}", Path.GetFileName(SourceFile.AbsolutePath));

                // Don't farm out creation of precomputed headers as it is the critical path task.
                CompileAction.bCanExecuteRemotely = CompileEnvironment.Config.PrecompiledHeaderAction != PrecompiledHeaderAction.Create;

                // @todo: XGE has problems remote compiling C++/CLI files that use .NET Framework 4.0
                if (CompileEnvironment.Config.CLRMode == CPPCLRMode.CLREnabled)
                {
                    CompileAction.bCanExecuteRemotely = false;
                }
            }
            return(Result);
        }
Ejemplo n.º 4
0
        static string GetCLArguments_Global(CPPEnvironment CompileEnvironment)
        {
            string Result = "";

            //Result += " /showIncludes";

            // Prevents the compiler from displaying its logo for each invocation.
            Result += " /nologo";

            // Enable intrinsic functions.
            Result += " /Oi";

            // Enable for static code analysis (where supported). Not treating analysis warnings as errors.
            // Result += " /analyze:WX-";

            // Pack struct members on 8-byte boundaries.
            Result += " /Zp8";

            // Calling convention - _cdecl
            Result += " /Gd";
            // Disable minimal rebuild
            Result += " /Gm-";
            // Security checks enabled
            Result += " /GS";

            // Separate functions for linker.
            Result += " /Gy";

            // Relaxes floating point precision semantics to allow more optimization.
            Result += " /fp:fast";

            // Compile into an .obj file, and skip linking.
            Result += " /c";

            // Allow 400% of the default memory allocation limit.
            Result += " /Zm400";

            // Allow large object files to avoid hitting the 2^16 section limit when running with -StressTestUnity.
            Result += " /bigobj";

            Result += " /Zc:wchar_t";
            Result += " /Zc:forScope";

            // Disable "The file contains a character that cannot be represented in the current code page" warning for non-US windows.
            Result += " /wd4819";

            if (BuildConfiguration.bUseSharedPCHs)
            {
                // @todo SharedPCH: Disable warning about PCH defines not matching .cpp defines.  We "cheat" these defines a little
                // bit to make shared PCHs work.  But it's totally safe.  Trust us.
                Result += " /wd4651";

                // @todo SharedPCH: Disable warning about redefining *API macros.  The PCH header is compiled with various DLLIMPORTs, but
                // when a module that uses that PCH header *IS* one of those imports, that module is compiled with EXPORTS, so the macro
                // is redefined on the command-line.  We need to clobber those defines to make shared PCHs work properly!
                Result += " /wd4005";
            }

            // If compiling as a DLL, set the relevant defines
            if (CompileEnvironment.Config.bIsBuildingDLL)
            {
                Result += " /D _WINDLL";
                Result += " /D _USRDLLundefined_EXPORTS";
            }

            //
            //	Debug
            //
            if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
            {
                // Disable compiler optimization.
                Result += " /Od";

                // Favor code size (especially useful for embedded platforms).
                Result += " /Os";

                // Allow inline method expansion unless E&C support is requested
                if (!BuildConfiguration.bSupportEditAndContinue)
                {
                    // Allow inline method expansion of any suitable.
                    Result += " /Ob2";
                }

                // Perform runtime checks for (s) stack frames and (u) unintialized variables
                // RTC1 == RTCsu
                Result += " /RTC1";
            }
            //
            //	Release and LTCG
            //
            else
            {
                // Maximum optimizations.
                Result += " /Ox";
                // Enable intrinsics
                Result += " /Oi";
                // Allow inline method expansion
                Result += " /Ob2";

                //
                // LTCG
                //
                if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Shipping)
                {
                    if (BuildConfiguration.bAllowLTCG)
                    {
                        // Enable link-time code generation.
                        Result += " /GL";
                    }
                }
            }

            //
            //	WinRT
            //
            if (CompileEnvironment.Config.bIsBuildingLibrary == false)
            {
                Result += " /ZW";
            }

            if (WinRTPlatform.ShouldCompileWinRT() == true)
            {
                // Prompt the user before reporting internal errors to Microsoft.
                Result += " /errorReport:prompt";

                // Enable C++ exception handling, but not C exceptions.
                Result += " /EHsc";

                // Disable "unreferenced formal parameter" warning since auto-included vccorlib.h triggers it
                Result += " /wd4100";

                // Disable "unreachable code" warning since auto-included vccorlib.h triggers it
                Result += " /wd4702";
            }
            else
            {
                Result += " /AI\"C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\vcpackages\"";

                Result += " /D USE_WINRT_MAIN=1";

                // WinRT requires exceptions!
//				if (CompileEnvironment.Config.bEnableExceptions)
                {
                    // Enable C++ exception handling, but not C exceptions.
                    Result += " /EHsc";
                }

                // Disable "unreferenced formal parameter" warning since auto-included vccorlib.h triggers it
                Result += " /wd4100";

                // Disable "unreachable code" warning since auto-included vccorlib.h triggers it
                Result += " /wd4702";

                // Disable "alignment of a member was sensitive to packing" warning since auto-included vccorlib.h triggers it
                Result += " /wd4121";

                // reinterpret_cast used between related classes: 'Platform::Object' and ...
                Result += " /wd4946";

                // macro redefinition
                Result += " /wd4005";

                //Result += " /showIncludes";
            }

            // If enabled, create debug information.
            if (CompileEnvironment.Config.bCreateDebugInfo)
            {
                // Store debug info in .pdb files.
                if (BuildConfiguration.bUsePDBFiles)
                {
                    // Create debug info suitable for E&C if wanted.
                    if (BuildConfiguration.bSupportEditAndContinue
                        // We only need to do this in debug as that's the only configuration that supports E&C.
                        && CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug)
                    {
                        Result += " /ZI";
                    }
                    // Regular PDB debug information.
                    else
                    {
                        Result += " /Zi";
                    }
                }
                // Store C7-format debug info in the .obj files, which is faster.
                else
                {
                    Result += " /Z7";
                }
            }

            // Specify the appropriate runtime library based on the platform and config.
            if (CompileEnvironment.Config.Target.Configuration == CPPTargetConfiguration.Debug && BuildConfiguration.bDebugBuildsActuallyUseDebugCRT)
            {
                Result += " /MDd";
            }
            else
            {
                Result += " /MD";
            }

            return(Result);
        }