Newer
Older
dub_jkp / source / dub / generators / cmake.d
@Sebastian Wilzbach Sebastian Wilzbach on 23 Feb 2017 4 KB Remove all trailing whitespace
  1. /**
  2. Generator for CMake build scripts
  3.  
  4. Copyright: © 2015 Steven Dwy
  5. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
  6. Authors: Steven Dwy
  7. */
  8. module dub.generators.cmake;
  9.  
  10. import dub.compilers.buildsettings;
  11. import dub.generators.generator;
  12. import dub.internal.vibecompat.core.log;
  13. import dub.internal.vibecompat.core.file;
  14. import dub.internal.vibecompat.inet.path;
  15. import dub.project;
  16.  
  17. import std.algorithm: map, uniq;
  18. import std.algorithm : stdsort = sort; // to avoid clashing with built-in sort
  19. import std.array: appender, join, replace;
  20. import std.stdio: File, write;
  21. import std.string: format;
  22.  
  23. class CMakeGenerator: ProjectGenerator
  24. {
  25. this(Project project)
  26. {
  27. super(project);
  28. }
  29.  
  30. override void generateTargets(GeneratorSettings settings, in TargetInfo[string] targets)
  31. {
  32. auto script = appender!(char[]);
  33. auto scripts = appender!(string[]);
  34. bool[string] visited;
  35. Path projectRoot = m_project.rootPackage.path;
  36. Path cmakeListsPath = projectRoot ~ "CMakeLists.txt";
  37.  
  38. foreach(name, info; targets)
  39. {
  40. if(visited.get(name, false))
  41. continue;
  42.  
  43. visited[name] = true;
  44. name = name.sanitize;
  45. string targetType;
  46. string libType;
  47. bool addTarget = true;
  48.  
  49. switch(info.buildSettings.targetType) with(TargetType)
  50. {
  51. case autodetect:
  52. throw new Exception("Don't know what to do about autodetect target type");
  53. case executable:
  54. targetType = "executable";
  55.  
  56. break;
  57. case dynamicLibrary:
  58. libType = "SHARED";
  59.  
  60. goto case;
  61. case library:
  62. case staticLibrary:
  63. targetType = "library";
  64.  
  65. break;
  66. case sourceLibrary:
  67. addTarget = false;
  68.  
  69. break;
  70. case none:
  71. continue;
  72. default:
  73. assert(false);
  74. }
  75.  
  76. script.put("include(UseD)\n");
  77. script.put(
  78. "add_d_conditions(VERSION %s DEBUG %s)\n".format(
  79. info.buildSettings.versions.dup.join(" "),
  80. info.buildSettings.debugVersions.dup.join(" "),
  81. )
  82. );
  83.  
  84. foreach(directory; info.buildSettings.importPaths)
  85. script.put("include_directories(%s)\n".format(directory.sanitizeSlashes));
  86.  
  87. if(addTarget)
  88. {
  89. script.put("add_%s(%s %s\n".format(targetType, name, libType));
  90.  
  91. foreach(file; info.buildSettings.sourceFiles)
  92. script.put(" %s\n".format(file.sanitizeSlashes));
  93.  
  94. script.put(")\n");
  95. script.put(
  96. "target_link_libraries(%s %s %s)\n".format(
  97. name,
  98. (info.dependencies ~ info.linkDependencies).dup.stdsort.uniq.map!(s => sanitize(s)).join(" "),
  99. info.buildSettings.libs.dup.join(" ")
  100. )
  101. );
  102. script.put(
  103. `set_target_properties(%s PROPERTIES TEXT_INCLUDE_DIRECTORIES "%s")`.format(
  104. name,
  105. info.buildSettings.stringImportPaths.map!(s => sanitizeSlashes(s)).join(";")
  106. ) ~ "\n"
  107. );
  108. }
  109.  
  110. string filename = (projectRoot ~ "%s.cmake".format(name)).toNativeString;
  111. File file = File(filename, "w");
  112.  
  113. file.write(script.data);
  114. file.close;
  115. script.shrinkTo(0);
  116. scripts.put(filename);
  117. }
  118.  
  119. if(!cmakeListsPath.existsFile)
  120. {
  121. logWarn("You must use a fork of CMake which has D support for these scripts to function properly.");
  122. logWarn("It is available at https://github.com/trentforkert/cmake");
  123. logInfo("Generating default CMakeLists.txt");
  124. script.put("cmake_minimum_required(VERSION 3.0)\n");
  125. script.put("project(%s D)\n".format(m_project.rootPackage.name));
  126.  
  127. foreach(path; scripts.data)
  128. script.put("include(%s)\n".format(path));
  129.  
  130. File file = File(cmakeListsPath.toNativeString, "w");
  131.  
  132. file.write(script.data);
  133. file.close;
  134. }
  135. }
  136. }
  137.  
  138. ///Transform a package name into a valid CMake target name.
  139. private string sanitize(string name)
  140. {
  141. return name.replace(":", "_");
  142. }
  143.  
  144. private string sanitizeSlashes(string path)
  145. {
  146. version(Windows)
  147. return path.replace("\\", "/");
  148. else
  149. return path;
  150. }