178 lines
4.1 KiB
Raku
178 lines
4.1 KiB
Raku
-- 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"
|
|
CC = "%CCOMPILER% %CBUILDFLAGS% %CDYNINCLUDES% %CINCLUDES% %CDEFINES% %CEXTRAFLAGS% -c -o %out% %in%"
|
|
CPROGRAM = "%CCOMPILER% %CBUILDFLAGS% %CLINKFLAGS% %CEXTRAFLAGS% -o %out% %in% %CLIBRARIES%"
|
|
AR = "%RM% %out% && ar cr %out% %in% && ranlib %out%"
|
|
|
|
CBUILDFLAGS = {"-g"}
|
|
CINCLUDES = EMPTY
|
|
CDEFINES = EMPTY
|
|
CEXTRAFLAGS = EMPTY
|
|
CLINKFLAGS = EMPTY
|
|
CDYNINCLUDES = EMPTY
|
|
CLIBRARIES = EMPTY
|
|
|
|
--- 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.CINCLUDES
|
|
if (type(cincludes) == "string") then
|
|
cincludes = {cincludes}
|
|
end
|
|
|
|
local includes = {}
|
|
for _, i in ipairs(cincludes) do
|
|
local _, _, p = string_find(i, "^-I[ \t]*(.+)$")
|
|
if p then
|
|
table_insert(includes, p)
|
|
end
|
|
end
|
|
|
|
local depends = calculate_dependencies(inputs[1], includes)
|
|
if not depends then
|
|
self:__error("could not determine the dependencies for ",
|
|
pm.rendertable(inputs))
|
|
end
|
|
if pm.verbose then
|
|
pm.message('"', inputs[1], '" 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
|
|
self.CDYNINCLUDES = self.CDYNINCLUDES..' "-I'..string_gsub(o[1], "/[^/]*$", "")..'"'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
}
|
|
|
|
-- These are the publically useful clauses.
|
|
|
|
cfile = simple_with_clike_dependencies {
|
|
class = "cfile",
|
|
command = {"%CC%"},
|
|
outputs = {"%U%-%I%.o"},
|
|
}
|
|
|
|
cprogram = simple {
|
|
class = "cprogram",
|
|
command = {"%CPROGRAM%"},
|
|
outputs = {"%U%-%I%"},
|
|
}
|
|
|
|
clibrary = simple {
|
|
class = "clibrary",
|
|
command = {
|
|
"%AR%"
|
|
},
|
|
outputs = {"%U%-%I%.a"},
|
|
}
|