Пример #1
0
        /// <summary>
        /// Try to parse the project file from the command line
        /// </summary>
        /// <param name="Arguments">The command line arguments</param>
        /// <param name="ProjectFile">The project file that was parsed</param>
        /// <returns>True if the project file was parsed, false otherwise</returns>
        private static bool TryParseProjectFileArgument(CommandLineArguments Arguments, out FileReference ProjectFile)
        {
            string CandidateProjectPath = null;

            // look for -project=<path>, if it does not exist check arguments for anything that has .uproject in it
            if (!Arguments.TryGetValue("-Project=", out CandidateProjectPath))
            {
                // Go through the argument list and try to match poorly (or well..) formed arguments like
                // EngineTest, EngineTest.uproject
                // Collaboration/FooProject
                // by checking for those in the native project list
                for (int Idx = 0; Idx < Arguments.Count; Idx++)
                {
                    if (Arguments[Idx][0] != '-' && Arguments[Idx].EndsWith(".uproject", StringComparison.OrdinalIgnoreCase))
                    {
                        CandidateProjectPath = Arguments[Idx];
                        Arguments.MarkAsUsed(Idx);
                        break;
                    }
                }
            }

            // We have a project file either via -project= or because there was something called .uproject in the arg list
            // so now validate it
            if (!string.IsNullOrEmpty(CandidateProjectPath))
            {
                FileReference CandidateProjectFile = new FileReference(CandidateProjectPath);

                // if the path doesn't exist then check native paths (ueprojectdirs)
                if (!FileReference.Exists(CandidateProjectFile))
                {
                    // clean everything the user provided to just the name and make sure it has the expected extension
                    string ProjectName = CandidateProjectFile.ChangeExtension("uproject").GetFileName();

                    // check native project paths (uprojectdirs)
                    IEnumerable <FileReference> NativeProjectFiles = NativeProjects.EnumerateProjectFiles();

                    CandidateProjectFile = NativeProjectFiles.Where(F => F.GetFileName().Equals(ProjectName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
                }

                if (CandidateProjectFile == null || !FileReference.Exists(CandidateProjectFile))
                {
                    // if we didn't find anything then throw an error as the user explicitly provided a uproject
                    throw new Exception(string.Format("Unable to find project file based on argument {0}", CandidateProjectPath));
                }

                Log.TraceVerbose("Resolved project argument {0} to {1}", CandidateProjectPath, CandidateProjectFile);
                ProjectFile = CandidateProjectFile;
                return(true);
            }

            FileReference InstalledProjectFile = UnrealBuildTool.GetInstalledProjectFile();

            if (InstalledProjectFile != null)
            {
                ProjectFile = InstalledProjectFile;
                return(true);
            }

            ProjectFile = null;
            return(false);
        }
        /// <summary>
        /// Parse a list of target descriptors from the command line
        /// </summary>
        /// <param name="Arguments">Command-line arguments</param>
        /// <param name="bUsePrecompiled">Whether to use a precompiled engine distribution</param>
        /// <param name="bSkipRulesCompile">Whether to skip compiling rules assemblies</param>
        /// <param name="TargetDescriptors">List of target descriptors</param>
        public static void ParseSingleCommandLine(CommandLineArguments Arguments, bool bUsePrecompiled, bool bSkipRulesCompile, List <TargetDescriptor> TargetDescriptors)
        {
            List <UnrealTargetPlatform>      Platforms      = new List <UnrealTargetPlatform>();
            List <UnrealTargetConfiguration> Configurations = new List <UnrealTargetConfiguration>();
            List <string> TargetNames = new List <string>();
            FileReference ProjectFile = Arguments.GetFileReferenceOrDefault("-Project=", null);

            // Settings for creating/using static libraries for the engine
            for (int ArgumentIndex = 0; ArgumentIndex < Arguments.Count; ArgumentIndex++)
            {
                string Argument = Arguments[ArgumentIndex];
                if (Argument.Length > 0 && Argument[0] != '-')
                {
                    // Mark this argument as used. We'll interpret it as one thing or another.
                    Arguments.MarkAsUsed(ArgumentIndex);

                    // Check if it's a project file argument
                    if (Argument.EndsWith(".uproject", StringComparison.OrdinalIgnoreCase))
                    {
                        FileReference NewProjectFile = new FileReference(Argument);
                        if (ProjectFile != null && ProjectFile != NewProjectFile)
                        {
                            throw new BuildException("Multiple project files specified on command line (first {0}, then {1})", ProjectFile, NewProjectFile);
                        }
                        ProjectFile = new FileReference(Argument);
                        continue;
                    }

                    // Split it into separate arguments
                    string[] InlineArguments = Argument.Split('+');

                    // Try to parse them as platforms
                    UnrealTargetPlatform ParsedPlatform;
                    if (UnrealTargetPlatform.TryParse(InlineArguments[0], out ParsedPlatform))
                    {
                        Platforms.Add(ParsedPlatform);
                        for (int InlineArgumentIdx = 1; InlineArgumentIdx < InlineArguments.Length; InlineArgumentIdx++)
                        {
                            Platforms.Add(UnrealTargetPlatform.Parse(InlineArguments[InlineArgumentIdx]));
                        }
                        continue;
                    }

                    // Try to parse them as configurations
                    UnrealTargetConfiguration ParsedConfiguration;
                    if (Enum.TryParse(InlineArguments[0], true, out ParsedConfiguration))
                    {
                        Configurations.Add(ParsedConfiguration);
                        for (int InlineArgumentIdx = 1; InlineArgumentIdx < InlineArguments.Length; InlineArgumentIdx++)
                        {
                            string InlineArgument = InlineArguments[InlineArgumentIdx];
                            if (!Enum.TryParse(InlineArgument, true, out ParsedConfiguration))
                            {
                                throw new BuildException("Invalid configuration '{0}'", InlineArgument);
                            }
                            Configurations.Add(ParsedConfiguration);
                        }
                        continue;
                    }

                    // Otherwise assume they are target names
                    TargetNames.AddRange(InlineArguments);
                }
            }

            if (Platforms.Count == 0)
            {
                throw new BuildException("No platforms specified for target");
            }
            if (Configurations.Count == 0)
            {
                throw new BuildException("No configurations specified for target");
            }

            // Make sure the project file exists, and make sure we're using the correct case.
            if (ProjectFile != null)
            {
                FileInfo ProjectFileInfo = FileUtils.FindCorrectCase(ProjectFile.ToFileInfo());
                if (!ProjectFileInfo.Exists)
                {
                    throw new BuildException("Unable to find project '{0}'.", ProjectFile);
                }
                ProjectFile = new FileReference(ProjectFileInfo);
            }

            // Expand all the platforms, architectures and configurations
            foreach (UnrealTargetPlatform Platform in Platforms)
            {
                // Make sure the platform is valid
                if (!InstalledPlatformInfo.IsValid(null, Platform, null, EProjectType.Code, InstalledPlatformState.Downloaded))
                {
                    if (!InstalledPlatformInfo.IsValid(null, Platform, null, EProjectType.Code, InstalledPlatformState.Supported))
                    {
                        throw new BuildException("The {0} platform is not supported from this engine distribution.", Platform);
                    }
                    else
                    {
                        throw new BuildException("Missing files required to build {0} targets. Enable {0} as an optional download component in the Epic Games Launcher.", Platform);
                    }
                }

                // Parse the architecture parameter, or get the default for the platform
                List <string> Architectures = new List <string>(Arguments.GetValues("-Architecture=", '+'));
                if (Architectures.Count == 0)
                {
                    Architectures.Add(UEBuildPlatform.GetBuildPlatform(Platform).GetDefaultArchitecture(ProjectFile));
                }

                foreach (string Architecture in Architectures)
                {
                    foreach (UnrealTargetConfiguration Configuration in Configurations)
                    {
                        // Create all the target descriptors for targets specified by type
                        foreach (string TargetTypeString in Arguments.GetValues("-TargetType="))
                        {
                            TargetType TargetType;
                            if (!Enum.TryParse(TargetTypeString, out TargetType))
                            {
                                throw new BuildException("Invalid target type '{0}'", TargetTypeString);
                            }

                            if (ProjectFile == null)
                            {
                                throw new BuildException("-TargetType=... requires a project file to be specified");
                            }
                            else
                            {
                                TargetNames.Add(RulesCompiler.CreateProjectRulesAssembly(ProjectFile, bUsePrecompiled, bSkipRulesCompile).GetTargetNameByType(TargetType, Platform, Configuration, Architecture, ProjectFile));
                            }
                        }

                        // Make sure we could parse something
                        if (TargetNames.Count == 0)
                        {
                            throw new BuildException("No target name was specified on the command-line.");
                        }

                        // Create all the target descriptors
                        foreach (string TargetName in TargetNames)
                        {
                            // If a project file was not specified see if we can find one
                            if (ProjectFile == null && NativeProjects.TryGetProjectForTarget(TargetName, out ProjectFile))
                            {
                                Log.TraceVerbose("Found project file for {0} - {1}", TargetName, ProjectFile);
                            }

                            // Create the target descriptor
                            TargetDescriptors.Add(new TargetDescriptor(ProjectFile, TargetName, Platform, Configuration, Architecture, Arguments));
                        }
                    }
                }
            }
        }
Пример #3
0
        private void AddProjectsForAllTargets(
            PlatformProjectGeneratorCollection PlatformProjectGenerators,
            List <FileReference> AllGames,
            out ProjectFile EngineProject,
            out List <ProjectFile> GameProjects,
            out Dictionary <FileReference, ProjectFile> ProgramProjects)
        {
            // As we're creating project files, we'll also keep track of whether we created an "engine" project and return that if we have one
            EngineProject   = null;
            GameProjects    = new List <ProjectFile>();
            ProgramProjects = new Dictionary <FileReference, ProjectFile>();

            // Find all of the target files.  This will filter out any modules or targets that don't
            // belong to platforms we're generating project files for.
            List <FileReference> AllTargetFiles = DiscoverTargets(AllGames);

            // Sort the targets by name. When we have multiple targets of a given type for a project, we'll use the order to determine which goes in the primary project file (so that client names with a suffix will go into their own project).
            AllTargetFiles = AllTargetFiles.OrderBy(x => x.FullName, StringComparer.OrdinalIgnoreCase).ToList();

            foreach (FileReference TargetFilePath in AllTargetFiles)
            {
                string TargetName = TargetFilePath.GetFileNameWithoutAnyExtensions();

                // Check to see if this is an Engine target.  That is, the target is located under the "Engine" folder
                bool IsEngineTarget           = false;
                bool IsEnterpriseTarget       = false;
                bool WantProjectFileForTarget = true;
                if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EngineDirectory))
                {
                    // This is an engine target
                    IsEngineTarget = true;

                    if (TargetFilePath.IsUnderDirectory(EngineSourceProgramsDirectory))
                    {
                        WantProjectFileForTarget = IncludeEnginePrograms;
                    }
                    else if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EngineSourceDirectory))
                    {
                        WantProjectFileForTarget = bIncludeEngineSource;
                    }
                }
                else if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseSourceDirectory))
                {
                    // This is an enterprise target
                    IsEnterpriseTarget = true;

                    if (TargetFilePath.IsUnderDirectory(EnterpriseSourceProgramsDirectory))
                    {
                        WantProjectFileForTarget = bIncludeEnterpriseSource && IncludeEnginePrograms;
                    }
                    else
                    {
                        WantProjectFileForTarget = bIncludeEnterpriseSource;
                    }
                }

                if (WantProjectFileForTarget)
                {
                    RulesAssembly RulesAssembly;

                    FileReference CheckProjectFile =
                        AllGames.FirstOrDefault(x => TargetFilePath.IsUnderDirectory(x.Directory));
                    if (CheckProjectFile == null)
                    {
                        if (TargetFilePath.IsUnderDirectory(UnrealBuildTool.EnterpriseDirectory))
                        {
                            RulesAssembly = RulesCompiler.CreateEnterpriseRulesAssembly(false, false);
                        }
                        else
                        {
                            RulesAssembly = RulesCompiler.CreateEngineRulesAssembly(false, false);
                        }
                    }
                    else
                    {
                        RulesAssembly = RulesCompiler.CreateProjectRulesAssembly(CheckProjectFile, false, false);
                    }

                    // Create target rules for all of the platforms and configuration combinations that we want to enable support for.
                    // Just use the current platform as we only need to recover the target type and both should be supported for all targets...
                    TargetRules TargetRulesObject = RulesAssembly.CreateTargetRules(TargetName,
                                                                                    BuildHostPlatform.Current.Platform, UnrealTargetConfiguration.Development, "", CheckProjectFile,
                                                                                    null);

                    bool IsProgramTarget = false;

                    DirectoryReference GameFolder = null;
                    string             ProjectFileNameBase;
                    if (TargetRulesObject.Type == TargetType.Program)
                    {
                        IsProgramTarget     = true;
                        ProjectFileNameBase = TargetName;
                    }
                    else if (IsEngineTarget)
                    {
                        ProjectFileNameBase = EngineProjectFileNameBase;
                    }
                    else if (IsEnterpriseTarget)
                    {
                        ProjectFileNameBase = EnterpriseProjectFileNameBase;
                    }
                    else
                    {
                        // Figure out which game project this target belongs to
                        FileReference ProjectInfo = FindGameContainingFile(AllGames, TargetFilePath);
                        if (ProjectInfo == null)
                        {
                            throw new BuildException("Found a non-engine target file (" + TargetFilePath +
                                                     ") that did not exist within any of the known game folders");
                        }

                        GameFolder          = ProjectInfo.Directory;
                        ProjectFileNameBase = ProjectInfo.GetFileNameWithoutExtension();
                    }

                    // Get the suffix to use for this project file. If we have multiple targets of the same type, we'll have to split them out into separate IDE project files.
                    string GeneratedProjectName = TargetRulesObject.GeneratedProjectName;
                    if (GeneratedProjectName == null)
                    {
                        ProjectFile ExistingProjectFile;
                        if (ProjectFileMap.TryGetValue(GetRiderProjectLocation(ProjectFileNameBase), out ExistingProjectFile) &&
                            ExistingProjectFile.ProjectTargets.Any(x => x.TargetRules.Type == TargetRulesObject.Type))
                        {
                            GeneratedProjectName = TargetRulesObject.Name;
                        }
                        else
                        {
                            GeneratedProjectName = ProjectFileNameBase;
                        }
                    }

                    FileReference ProjectFilePath = GetRiderProjectLocation(GeneratedProjectName);
                    if (TargetRulesObject.Type == TargetType.Game || TargetRulesObject.Type == TargetType.Client ||
                        TargetRulesObject.Type == TargetType.Server)
                    {
                        // Allow platforms to generate stub projects here...
                        PlatformProjectGenerators.GenerateGameProjectStubs(
                            InGenerator: this,
                            InTargetName: TargetName,
                            InTargetFilepath: TargetFilePath.FullName,
                            InTargetRules: TargetRulesObject,
                            InPlatforms: SupportedPlatforms,
                            InConfigurations: SupportedConfigurations);
                    }

                    DirectoryReference BaseFolder;
                    if (IsProgramTarget)
                    {
                        BaseFolder = TargetFilePath.Directory;
                    }
                    else if (IsEngineTarget)
                    {
                        BaseFolder = UnrealBuildTool.EngineDirectory;
                    }
                    else if (IsEnterpriseTarget)
                    {
                        BaseFolder = UnrealBuildTool.EnterpriseDirectory;
                    }
                    else
                    {
                        BaseFolder = GameFolder;
                    }

                    bool        bProjectAlreadyExisted;
                    ProjectFile ProjectFile = FindOrAddProject(ProjectFilePath, BaseFolder,
                                                               true, out bProjectAlreadyExisted);
                    ProjectFile.IsForeignProject =
                        CheckProjectFile != null && !NativeProjects.IsNativeProject(CheckProjectFile);
                    ProjectFile.IsGeneratedProject = true;
                    ProjectFile.IsStubProject      = UnrealBuildTool.IsProjectInstalled();
                    if (TargetRulesObject.bBuildInSolutionByDefault.HasValue)
                    {
                        ProjectFile.ShouldBuildByDefaultForSolutionTargets =
                            TargetRulesObject.bBuildInSolutionByDefault.Value;
                    }

                    // Add the project to the right output list
                    if (IsProgramTarget)
                    {
                        ProgramProjects[TargetFilePath] = ProjectFile;
                    }
                    else if (IsEngineTarget)
                    {
                        EngineProject = ProjectFile;
                        if (UnrealBuildTool.IsEngineInstalled())
                        {
                            // Allow engine projects to be created but not built for Installed Engine builds
                            EngineProject.IsForeignProject   = false;
                            EngineProject.IsGeneratedProject = true;
                            EngineProject.IsStubProject      = true;
                        }
                    }
                    else if (IsEnterpriseTarget)
                    {
                        ProjectFile EnterpriseProject = ProjectFile;
                        if (UnrealBuildTool.IsEnterpriseInstalled())
                        {
                            // Allow enterprise projects to be created but not built for Installed Engine builds
                            EnterpriseProject.IsForeignProject   = false;
                            EnterpriseProject.IsGeneratedProject = true;
                            EnterpriseProject.IsStubProject      = true;
                        }
                    }
                    else
                    {
                        if (!bProjectAlreadyExisted)
                        {
                            GameProjects.Add(ProjectFile);

                            // Add the .uproject file for this game/template
                            FileReference UProjectFilePath =
                                FileReference.Combine(BaseFolder, ProjectFileNameBase + ".uproject");
                            if (FileReference.Exists(UProjectFilePath))
                            {
                                ProjectFile.AddFileToProject(UProjectFilePath, BaseFolder);
                            }
                            else
                            {
                                throw new BuildException(
                                          "Not expecting to find a game with no .uproject file.  File '{0}' doesn't exist",
                                          UProjectFilePath);
                            }
                        }
                    }

                    foreach (ProjectTarget ExistingProjectTarget in ProjectFile.ProjectTargets)
                    {
                        if (ExistingProjectTarget.TargetRules.Type == TargetRulesObject.Type)
                        {
                            throw new BuildException(
                                      "Not expecting project {0} to already have a target rules of with configuration name {1} ({2}) while trying to add: {3}",
                                      ProjectFilePath, TargetRulesObject.Type.ToString(),
                                      ExistingProjectTarget.TargetRules.ToString(), TargetRulesObject.ToString());
                        }

                        // Not expecting to have both a game and a program in the same project.  These would alias because we share the project and solution configuration names (just because it makes sense to)
                        if ((ExistingProjectTarget.TargetRules.Type == TargetType.Game &&
                             TargetRulesObject.Type == TargetType.Program) ||
                            (ExistingProjectTarget.TargetRules.Type == TargetType.Program &&
                             TargetRulesObject.Type == TargetType.Game))
                        {
                            throw new BuildException(
                                      "Not expecting project {0} to already have a Game/Program target ({1}) associated with it while trying to add: {2}",
                                      ProjectFilePath, ExistingProjectTarget.TargetRules.ToString(),
                                      TargetRulesObject.ToString());
                        }
                    }

                    ProjectTarget ProjectTarget = new ProjectTarget()
                    {
                        TargetRules           = TargetRulesObject,
                        TargetFilePath        = TargetFilePath,
                        ProjectFilePath       = ProjectFilePath,
                        UnrealProjectFilePath = CheckProjectFile,
                        SupportedPlatforms    = TargetRulesObject.GetSupportedPlatforms()
                                                .Where(x => UEBuildPlatform.GetBuildPlatform(x, true) != null).ToArray(),
                        CreateRulesDelegate = (Platform, Configuration) =>
                                              RulesAssembly.CreateTargetRules(TargetName, Platform, Configuration, "", CheckProjectFile,
                                                                              null)
                    };

                    ProjectFile.ProjectTargets.Add(ProjectTarget);

                    // Make sure the *.Target.cs file is in the project.
                    ProjectFile.AddFileToProject(TargetFilePath, BaseFolder);

                    Log.TraceVerbose("Generating target {0} for {1}", TargetRulesObject.Type.ToString(),
                                     ProjectFilePath);
                }
            }
        }