// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Text; using System.IO; namespace UnrealBuildTool { /// /// Represents a folder within the master project (e.g. Visual Studio solution) /// public class CMakefileFolder : MasterProjectFolder { /// /// Constructor /// public CMakefileFolder( ProjectFileGenerator InitOwnerProjectFileGenerator, string InitFolderName ) : base(InitOwnerProjectFileGenerator, InitFolderName) { } } public class CMakefileProjectFile : ProjectFile { public CMakefileProjectFile( string InitFilePath ) : base(InitFilePath) { } } /// /// CMakefile project file generator implementation /// public class CMakefileGenerator : ProjectFileGenerator { /// True if intellisense data should be generated (takes a while longer) bool bGenerateIntelliSenseData = false; /// True if we should include IntelliSense data in the generated project files when possible override public bool ShouldGenerateIntelliSenseData() { return bGenerateIntelliSenseData; } /// File extension for project files we'll be generating (e.g. ".vcxproj") override public string ProjectFileExtension { get { return ".txt"; } } protected override bool WriteMasterProjectFile( ProjectFile UBTProject ) { bool bSuccess = true; return bSuccess; } private bool WriteCMakeLists() { string BuildCommand = ""; var FileName = "CMakeLists.txt"; var CMakefileContent = new StringBuilder(); var CMakeSectionEnd = " )\n\n"; var CMakeSourceFilesList = "set(SOURCE_FILES \n"; var CMakeHeaderFilesList = "set(HEADER_FILES \n"; var CMakeConfigFilesList = "set(CONFIG_FILES \n"; var CMakeGameRootPath = ""; var CMakeUE4RootPath = "set(UE4_ROOT_PATH " + Path.GetFullPath(ProjectFileGenerator.RootRelativePath) + ")\n"; string GameProjectPath = ""; string GameProjectFile = ""; string CMakeGameProjectFile = ""; if (!String.IsNullOrEmpty (GameProjectName)) { CMakeGameRootPath = "set(GAME_ROOT_PATH \"" + UnrealBuildTool.GetUProjectPath() + "\")\n"; GameProjectPath = UnrealBuildTool.GetUProjectPath (); GameProjectFile = UnrealBuildTool.GetUProjectFile (); CMakeGameProjectFile = "set(GAME_PROJECT_FILE \"" + GameProjectFile + "\")\n"; BuildCommand = "set(BUILD mono ${UE4_ROOT_PATH}/Engine/Binaries/DotNET/UnrealBuildTool.exe )\n"; // -project=\"\\\"" + UnrealBuildTool.GetUProjectPath () + "/" + GameProjectName + ".uproject\\\"\")\n"; } else { BuildCommand = "set(BUILD bash ${UE4_ROOT_PATH}/Engine/Build/BatchFiles/Linux/Build.sh)\n"; } CMakefileContent.Append( "# Makefile generated by CMakefileGenerator.cs\n" + "# *DO NOT EDIT*\n\n" + "cmake_minimum_required (VERSION 2.6)\n" + "project (UE4)\n\n" + CMakeUE4RootPath + CMakeGameProjectFile + BuildCommand + CMakeGameRootPath + "\n" ); // Create SourceFiles, HeaderFiles, and ConfigFiles sections. var AllModuleFiles = DiscoverModules(); foreach (string CurModuleFile in AllModuleFiles) { var FoundFiles = SourceFileSearch.FindModuleSourceFiles(CurModuleFile, ExcludeNoRedistFiles: bExcludeNoRedistFiles); foreach (string CurSourceFile in FoundFiles) { string SourceFileRelativeToRoot = Utils.MakePathRelativeTo(CurSourceFile, Path.Combine(EngineRelativePath)); // Exclude Windows, Mac, and iOS only files/folders. // This got ugly quick. if (!SourceFileRelativeToRoot.Contains ("Source/ThirdParty/") && !SourceFileRelativeToRoot.Contains ("/Windows/") && !SourceFileRelativeToRoot.Contains ("/Mac/") && !SourceFileRelativeToRoot.Contains ("/IOS/") && !SourceFileRelativeToRoot.Contains ("/iOS/") && !SourceFileRelativeToRoot.Contains ("/VisualStudioSourceCodeAccess/") && !SourceFileRelativeToRoot.Contains ("/XCodeSourceCodeAccess/") && !SourceFileRelativeToRoot.Contains ("/WmfMedia/") && !SourceFileRelativeToRoot.Contains ("/IOSDeviceProfileSelector/") && !SourceFileRelativeToRoot.Contains ("/WindowsDeviceProfileSelector/") && !SourceFileRelativeToRoot.Contains ("/WindowsMoviePlayer/") && !SourceFileRelativeToRoot.Contains ("/AppleMoviePlayer/") && !SourceFileRelativeToRoot.Contains ("/MacGraphicsSwitching/") && !SourceFileRelativeToRoot.Contains ("/Apple/") && !SourceFileRelativeToRoot.Contains ("/WinRT/") ) { if (SourceFileRelativeToRoot.EndsWith (".cpp")) { if (!SourceFileRelativeToRoot.StartsWith ("..") && !Path.IsPathRooted (SourceFileRelativeToRoot)) { // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot; CMakeSourceFilesList += ("\t\"${UE4_ROOT_PATH}/Engine/" + SourceFileRelativeToRoot + "\"\n"); } else { if (String.IsNullOrEmpty (GameProjectName)) { // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3); CMakeSourceFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring (3) + "\"\n"); } else { CMakeSourceFilesList += ("\t\"${GAME_ROOT_PATH}/" + Utils.MakePathRelativeTo (CurSourceFile, GameProjectPath) + "\"\n"); } } } if (SourceFileRelativeToRoot.EndsWith (".h")) { if (!SourceFileRelativeToRoot.StartsWith ("..") && !Path.IsPathRooted (SourceFileRelativeToRoot)) { // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot; CMakeHeaderFilesList += ("\t\"${UE4_ROOT_PATH}/Engine/" + SourceFileRelativeToRoot + "\"\n"); } else { if (String.IsNullOrEmpty (GameProjectName)) { // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3); CMakeHeaderFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring (3) + "\"\n"); } else { CMakeHeaderFilesList += ("\t\"${GAME_ROOT_PATH}/" + Utils.MakePathRelativeTo (CurSourceFile, GameProjectPath) + "\"\n"); } } } if (SourceFileRelativeToRoot.EndsWith (".cs")) { if (!SourceFileRelativeToRoot.StartsWith ("..") && !Path.IsPathRooted (SourceFileRelativeToRoot)) { // SourceFileRelativeToRoot = "Engine/" + SourceFileRelativeToRoot; CMakeConfigFilesList += ("\t\"${UE4_ROOT_PATH}/Engine/" + SourceFileRelativeToRoot + "\"\n"); } else { if (String.IsNullOrEmpty (GameProjectName)) { // SourceFileRelativeToRoot = SourceFileRelativeToRoot.Substring (3); CMakeConfigFilesList += ("\t\"" + SourceFileRelativeToRoot.Substring (3) + "\"\n"); } else { CMakeConfigFilesList += ("\t\"${GAME_ROOT_PATH}/" + Utils.MakePathRelativeTo (CurSourceFile, GameProjectPath) + "\"\n"); }; } } } } } // Add section end to section strings; CMakeSourceFilesList += CMakeSectionEnd; CMakeHeaderFilesList += CMakeSectionEnd; CMakeConfigFilesList += CMakeSectionEnd; // Append sections to the CMakeLists.txt file CMakefileContent.Append (CMakeSourceFilesList); CMakefileContent.Append (CMakeHeaderFilesList); CMakefileContent.Append (CMakeConfigFilesList); string CMakeProjectCmdArg = ""; foreach (string TargetFilePath in DiscoverTargets()) { var TargetName = Utils.GetFilenameWithoutAnyExtensions(TargetFilePath); // Remove both ".cs" and ". foreach (UnrealTargetConfiguration CurConfiguration in Enum.GetValues(typeof(UnrealTargetConfiguration))) { if (CurConfiguration != UnrealTargetConfiguration.Unknown && CurConfiguration != UnrealTargetConfiguration.Development) { if (UnrealBuildTool.IsValidConfiguration(CurConfiguration)) { if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor")) { CMakeProjectCmdArg = " -project=\"\\\"${GAME_PROJECT_FILE}\\\"\""; } var ConfName = Enum.GetName(typeof(UnrealTargetConfiguration), CurConfiguration); CMakefileContent.Append(String.Format("add_custom_target({0}-Linux-{1} ${{BUILD}} {2} {0} Linux {1} $(ARGS))\n", TargetName, ConfName, CMakeProjectCmdArg)); } } } if (TargetName == GameProjectName || TargetName == (GameProjectName + "Editor")) { CMakeProjectCmdArg = " -project=\"\\\"${GAME_PROJECT_FILE}\\\"\""; } CMakefileContent.Append(String.Format("add_custom_target({0} ${{BUILD}} {1} {0} Linux Development $(ARGS) SOURCES ${{SOURCE_FILES}} ${{HEADER_FILES}} ${{CONFIG_FILES}})\n\n", TargetName, CMakeProjectCmdArg)); } var FullFileName = Path.Combine(MasterProjectRelativePath, FileName); return WriteFileIfChanged(FullFileName, CMakefileContent.ToString()); } /// ProjectFileGenerator interface //protected override bool WriteMasterProjectFile( ProjectFile UBTProject ) protected override bool WriteProjectFiles () { return WriteCMakeLists(); } /// ProjectFileGenerator interface public override MasterProjectFolder AllocateMasterProjectFolder( ProjectFileGenerator InitOwnerProjectFileGenerator, string InitFolderName ) { return new CMakefileFolder( InitOwnerProjectFileGenerator, InitFolderName ); } /// ProjectFileGenerator interface /// /// Allocates a generator-specific project file object /// /// Path to the project file /// The newly allocated project file object protected override ProjectFile AllocateProjectFile( string InitFilePath ) { return new CMakefileProjectFile( InitFilePath ); } /// ProjectFileGenerator interface public override void CleanProjectFiles(string InMasterProjectRelativePath, string InMasterProjectName, string InIntermediateProjectFilesPath) { } } }