123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- -- $Id$
- -- $HeadURL: https://primemover.svn.sf.net/svnroot/primemover/pm/lib/c.pm $
- -- $LastChangedDate: 2007-02-24 01:37:06 +0000 (Sat, 24 Feb 2007) $
- -- pm includefile to compile *host* C programs.
- -- Standard Lua boilerplate.
- local io_open = io.open
- local string_gsub = string.gsub
- local string_gfind = string.gfind
- local string_find = string.find
- local table_insert = table.insert
- local table_getn = table.getn
- local filetime = pm.filetime
- -- Define some variables.
- CCOMPILER = "gcc"
- CXXCOMPILER = "g++"
- CC = "%CCOMPILER% %CBUILDFLAGS% %CDYNINCLUDES:cincludes% %CINCLUDES:cincludes% %CDEFINES:cdefines% %CEXTRAFLAGS% -c -o %out% %in%"
- CXX = "%CXXCOMPILER% %CBUILDFLAGS% %CDYNINCLUDES:cincludes% %CINCLUDES:cincludes% %CDEFINES:cdefines% %CEXTRAFLAGS% -c -o %out% %in%"
- CPROGRAM = "%CCOMPILER% %CBUILDFLAGS% %CLINKFLAGS% %CEXTRAFLAGS% -o %out% %in% %CLIBRARIES:clibraries%"
- CXXPROGRAM = "%CXXCOMPILER% %CBUILDFLAGS% %CLINKFLAGS% %CEXTRAFLAGS% -o %out% %in% %CLIBRARIES:clibraries%"
- CLIBRARY = "rm -f %out% && ar cr %out% %in% && ranlib %out%"
- CBUILDFLAGS = {"-g"}
- CINCLUDES = EMPTY
- CDEFINES = EMPTY
- CEXTRAFLAGS = EMPTY
- CLINKFLAGS = EMPTY
- CDYNINCLUDES = EMPTY
- CLIBRARIES = EMPTY
- --- Custom string modifiers -------------------------------------------------
- local function prepend(rule, arg, prefix)
- if (arg == EMPTY) then
- return EMPTY
- end
-
- local t = {}
- for i, j in ipairs(arg) do
- t[i] = prefix..j
- end
- return t
- end
- function pm.stringmodifier.cincludes(rule, arg)
- return prepend(rule, arg, "-I")
- end
- function pm.stringmodifier.cdefines(rule, arg)
- return prepend(rule, arg, "-D")
- end
- function pm.stringmodifier.clibraries(rule, arg)
- if (arg == EMPTY) then
- return EMPTY
- end
-
- local t = {}
- for i, j in ipairs(arg) do
- if string_find(j, "%.a$") then
- t[i] = j
- else
- t[i] = "-l"..j
- end
- end
- return t
- end
- --- Manage C file dependencies ----------------------------------------------
- local dependency_cache = {}
- local function calculate_dependencies(filename, includes)
- -- Cache values, so we don't recalculate dependencies needlessly.
-
- local o = dependency_cache[filename]
- if o then
- return o
- end
-
- local deps = {}
- deps[filename] = true
-
- local calcdeps = 0
- calcdeps = function(filename, file)
- file = file or io_open(filename)
- if not file then
- return
- end
-
- local localincludes = string_gsub(filename, "/[^/]*$", "")
- if localincludes then
- localincludes = {localincludes, unpack(includes)}
- else
- localincludes = includes
- end
-
- for line in file:lines() do
- local _, _, f = string_find(line, '^[ \t]*#[ \t]*include[ \t]*["<]([^"]+)[">]')
- if f then
- for _, path in ipairs(localincludes) do
- local subfilename = path.."/"..f
- local subfile = io_open(subfilename)
- if subfile then
- if not deps[subfilename] then
- deps[subfilename] = true
- calcdeps(subfilename, subfile)
- end
- break
- end
- end
- end
- end
-
- -- Explicit close to avoid having to wait for the garbage collector
- -- to free up the underlying fd.
-
- file:close()
- end
-
- calcdeps(filename)
- o = {}
- for i, _ in pairs(deps) do
- table_insert(o, i)
- end
-
- dependency_cache[filename] = o
- return o
- end
- -- This clause specialises 'simple' to add support for smart dependencies of C
- -- files.
- simple_with_clike_dependencies = simple {
- class = "simple_with_clike_dependencies",
- makedepends = {"%CDEPENDS%"},
- __init = function(self, p)
- simple.__init(self, p)
-
- -- If we're a class, don't verify.
-
- if ((type(p) == "table") and p.class) then
- return
- end
- -- If dynamicheaders is an object, turn it into a singleton list.
-
- if self.dynamicheaders then
- if (type(self.dynamicheaders) ~= "table") then
- self:__error("doesn't know what to do with dynamicheaders, which ",
- "should be a list or an object but was a ", type(self.dynamicheaders))
- end
- if self.dynamicheaders.class then
- self.dynamicheaders = {self.dynamicheaders}
- end
- end
- end,
-
- __dependencies = function(self, inputs, outputs)
- local cincludes = self:__index("CINCLUDES")
- if (type(cincludes) == "string") then
- cincludes = {cincludes}
- end
-
- local includes = {}
- for _, i in ipairs(cincludes) do
- table_insert(includes, self:__expand(i))
- end
-
- local input = self:__expand(inputs[1])
- local depends = calculate_dependencies(input, includes)
- if not depends then
- self:__error("could not determine the dependencies for ",
- pm.rendertable({input}))
- end
- if pm.verbose then
- pm.message('"', input, '" appears to depend on ',
- pm.rendertable(depends))
- end
- return depends
- end,
-
- __buildadditionalchildren = function(self)
- self.CDYNINCLUDES = {}
- if self.dynamicheaders then
- for _, i in ipairs(self.dynamicheaders) do
- local o = i:__build()
- if o[1] then
- table_insert(self.CDYNINCLUDES, (string_gsub(o[1], "/[^/]*$", "")))
- end
- end
- end
- -- If no paths on the list, replace the list with EMPTY so it doesn't
- -- expand to anything.
- if (table_getn(self.CDYNINCLUDES) == 0) then
- self.CDYNINCLUDES = EMPTY
- end
- end
- }
- -- These are the publically useful clauses.
- cfile = simple_with_clike_dependencies {
- class = "cfile",
- command = {"%CC%"},
- outputs = {"%U%-%I%.o"},
- }
- cxxfile = simple_with_clike_dependencies {
- class = "cxxfile",
- command = {"%CXX%"},
- outputs = {"%U%-%I%.o"},
- }
- cprogram = simple {
- class = "cprogram",
- command = {"%CPROGRAM%"},
- outputs = {"%U%-%I%"},
- }
- cxxprogram = simple {
- class = "cxxprogram",
- command = {"%CXXPROGRAM%"},
- outputs = {"%U%-%I%"},
- }
- clibrary = simple {
- class = "clibrary",
- command = {
- "%CLIBRARY%"
- },
- outputs = {"%U%-%I%.a"},
- }
|