c.pm 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. -- $Id$
  2. -- $HeadURL: https://primemover.svn.sf.net/svnroot/primemover/pm/lib/c.pm $
  3. -- $LastChangedDate: 2007-02-24 01:37:06 +0000 (Sat, 24 Feb 2007) $
  4. -- pm includefile to compile *host* C programs.
  5. -- Standard Lua boilerplate.
  6. local io_open = io.open
  7. local string_gsub = string.gsub
  8. local string_gfind = string.gfind
  9. local string_find = string.find
  10. local table_insert = table.insert
  11. local table_getn = table.getn
  12. local filetime = pm.filetime
  13. -- Define some variables.
  14. CCOMPILER = "gcc"
  15. CXXCOMPILER = "g++"
  16. CC = "%CCOMPILER% %CBUILDFLAGS% %CDYNINCLUDES:cincludes% %CINCLUDES:cincludes% %CDEFINES:cdefines% %CEXTRAFLAGS% -c -o %out% %in%"
  17. CXX = "%CXXCOMPILER% %CBUILDFLAGS% %CDYNINCLUDES:cincludes% %CINCLUDES:cincludes% %CDEFINES:cdefines% %CEXTRAFLAGS% -c -o %out% %in%"
  18. CPROGRAM = "%CCOMPILER% %CBUILDFLAGS% %CLINKFLAGS% %CEXTRAFLAGS% -o %out% %in% %CLIBRARIES:clibraries%"
  19. CXXPROGRAM = "%CXXCOMPILER% %CBUILDFLAGS% %CLINKFLAGS% %CEXTRAFLAGS% -o %out% %in% %CLIBRARIES:clibraries%"
  20. CLIBRARY = "rm -f %out% && ar cr %out% %in% && ranlib %out%"
  21. CBUILDFLAGS = {"-g"}
  22. CINCLUDES = EMPTY
  23. CDEFINES = EMPTY
  24. CEXTRAFLAGS = EMPTY
  25. CLINKFLAGS = EMPTY
  26. CDYNINCLUDES = EMPTY
  27. CLIBRARIES = EMPTY
  28. --- Custom string modifiers -------------------------------------------------
  29. local function prepend(rule, arg, prefix)
  30. if (arg == EMPTY) then
  31. return EMPTY
  32. end
  33. local t = {}
  34. for i, j in ipairs(arg) do
  35. t[i] = prefix..j
  36. end
  37. return t
  38. end
  39. function pm.stringmodifier.cincludes(rule, arg)
  40. return prepend(rule, arg, "-I")
  41. end
  42. function pm.stringmodifier.cdefines(rule, arg)
  43. return prepend(rule, arg, "-D")
  44. end
  45. function pm.stringmodifier.clibraries(rule, arg)
  46. if (arg == EMPTY) then
  47. return EMPTY
  48. end
  49. local t = {}
  50. for i, j in ipairs(arg) do
  51. if string_find(j, "%.a$") then
  52. t[i] = j
  53. else
  54. t[i] = "-l"..j
  55. end
  56. end
  57. return t
  58. end
  59. --- Manage C file dependencies ----------------------------------------------
  60. local dependency_cache = {}
  61. local function calculate_dependencies(filename, includes)
  62. -- Cache values, so we don't recalculate dependencies needlessly.
  63. local o = dependency_cache[filename]
  64. if o then
  65. return o
  66. end
  67. local deps = {}
  68. deps[filename] = true
  69. local calcdeps = 0
  70. calcdeps = function(filename, file)
  71. file = file or io_open(filename)
  72. if not file then
  73. return
  74. end
  75. local localincludes = string_gsub(filename, "/[^/]*$", "")
  76. if localincludes then
  77. localincludes = {localincludes, unpack(includes)}
  78. else
  79. localincludes = includes
  80. end
  81. for line in file:lines() do
  82. local _, _, f = string_find(line, '^[ \t]*#[ \t]*include[ \t]*["<]([^"]+)[">]')
  83. if f then
  84. for _, path in ipairs(localincludes) do
  85. local subfilename = path.."/"..f
  86. local subfile = io_open(subfilename)
  87. if subfile then
  88. if not deps[subfilename] then
  89. deps[subfilename] = true
  90. calcdeps(subfilename, subfile)
  91. end
  92. break
  93. end
  94. end
  95. end
  96. end
  97. -- Explicit close to avoid having to wait for the garbage collector
  98. -- to free up the underlying fd.
  99. file:close()
  100. end
  101. calcdeps(filename)
  102. o = {}
  103. for i, _ in pairs(deps) do
  104. table_insert(o, i)
  105. end
  106. dependency_cache[filename] = o
  107. return o
  108. end
  109. -- This clause specialises 'simple' to add support for smart dependencies of C
  110. -- files.
  111. simple_with_clike_dependencies = simple {
  112. class = "simple_with_clike_dependencies",
  113. makedepends = {"%CDEPENDS%"},
  114. __init = function(self, p)
  115. simple.__init(self, p)
  116. -- If we're a class, don't verify.
  117. if ((type(p) == "table") and p.class) then
  118. return
  119. end
  120. -- If dynamicheaders is an object, turn it into a singleton list.
  121. if self.dynamicheaders then
  122. if (type(self.dynamicheaders) ~= "table") then
  123. self:__error("doesn't know what to do with dynamicheaders, which ",
  124. "should be a list or an object but was a ", type(self.dynamicheaders))
  125. end
  126. if self.dynamicheaders.class then
  127. self.dynamicheaders = {self.dynamicheaders}
  128. end
  129. end
  130. end,
  131. __dependencies = function(self, inputs, outputs)
  132. local cincludes = self:__index("CINCLUDES")
  133. if (type(cincludes) == "string") then
  134. cincludes = {cincludes}
  135. end
  136. local includes = {}
  137. for _, i in ipairs(cincludes) do
  138. table_insert(includes, self:__expand(i))
  139. end
  140. local input = self:__expand(inputs[1])
  141. local depends = calculate_dependencies(input, includes)
  142. if not depends then
  143. self:__error("could not determine the dependencies for ",
  144. pm.rendertable({input}))
  145. end
  146. if pm.verbose then
  147. pm.message('"', input, '" appears to depend on ',
  148. pm.rendertable(depends))
  149. end
  150. return depends
  151. end,
  152. __buildadditionalchildren = function(self)
  153. self.CDYNINCLUDES = {}
  154. if self.dynamicheaders then
  155. for _, i in ipairs(self.dynamicheaders) do
  156. local o = i:__build()
  157. if o[1] then
  158. table_insert(self.CDYNINCLUDES, (string_gsub(o[1], "/[^/]*$", "")))
  159. end
  160. end
  161. end
  162. -- If no paths on the list, replace the list with EMPTY so it doesn't
  163. -- expand to anything.
  164. if (table_getn(self.CDYNINCLUDES) == 0) then
  165. self.CDYNINCLUDES = EMPTY
  166. end
  167. end
  168. }
  169. -- These are the publically useful clauses.
  170. cfile = simple_with_clike_dependencies {
  171. class = "cfile",
  172. command = {"%CC%"},
  173. outputs = {"%U%-%I%.o"},
  174. }
  175. cxxfile = simple_with_clike_dependencies {
  176. class = "cxxfile",
  177. command = {"%CXX%"},
  178. outputs = {"%U%-%I%.o"},
  179. }
  180. cprogram = simple {
  181. class = "cprogram",
  182. command = {"%CPROGRAM%"},
  183. outputs = {"%U%-%I%"},
  184. }
  185. cxxprogram = simple {
  186. class = "cxxprogram",
  187. command = {"%CXXPROGRAM%"},
  188. outputs = {"%U%-%I%"},
  189. }
  190. clibrary = simple {
  191. class = "clibrary",
  192. command = {
  193. "%CLIBRARY%"
  194. },
  195. outputs = {"%U%-%I%.a"},
  196. }