1
0
mirror of https://github.com/elua/elua.git synced 2025-01-25 01:02:54 +08:00

Targets can be reffered to by name now

Now a target can be reffered to also by its name, not only by the
corresponding _target object. Also added 'utils.lua' as a separate
file in utils/ (it used to be a part of build.lua)
This commit is contained in:
Bogdan Marinescu 2011-03-05 20:22:11 +02:00
parent bcc81ba5fe
commit 77ac825d39
3 changed files with 221 additions and 171 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
.build/
*.hex
*.elf
*.o
*.obj
*.exe
*.bin
*.pyc
inc/romfiles.h
*.swp
.sconf_temp/
.sconsign.dblite
config.log

View File

@ -4,10 +4,7 @@ module( ..., package.seeall )
local lfs = require "lfs"
local sf = string.format
-- Taken from Lake
local dir_sep = package.config:sub( 1, 1 )
local is_windows = dir_sep == '\\'
utils = require "utils.utils"
-------------------------------------------------------------------------------
-- Various helpers
@ -46,6 +43,13 @@ local function table_to_string( t )
return t
end
-- Helper: return the extended type of an object (takes into account __type)
local function exttype( o )
local t = type( o )
if t == "table" and o.__type then t = o:__type() end
return t
end
---------------------------------------
-- Table utils
-- (from http://lua-users.org/wiki/TableUtils)
@ -85,143 +89,6 @@ function table.tostring( tbl )
return "{" .. table.concat( result, "," ) .. "}"
end
-------------------------------------------------------------------------------
-- Public utilities
utils = { dir_sep = dir_sep }
-- Converts a string with items separated by 'sep' into a table
utils.string_to_table = function( s, sep )
if type( s ) ~= "string" then return end
sep = sep or ' '
if s:sub( -1, -1 ) ~= sep then s = s .. sep end
s = s:gsub( sf( "^%s*", sep ), "" )
local t = {}
local fmt = sf( "(.-)%s+", sep )
for w in s:gmatch( fmt ) do table.insert( t, w ) end
return t
end
-- Split a file name into 'path part' and 'extension part'
utils.split_path = function( s )
local pos
for i = #s, 1, -1 do
if s:sub( i, i ) == "." then
pos = i
break
end
end
if pos then return s:sub( 1, pos - 1 ), s:sub( pos ) end
return s
end
-- Replace the extension of a give file name
utils.replace_extension = function( s, newext )
local p, e = utils.split_path( s )
if e then s = p .. "." .. newext end
return s
end
-- Return 'true' if building from Windows, false otherwise
utils.is_windows = function()
return is_windows
end
-- Prepend each component of a 'pat'-separated string with 'prefix'
utils.prepend_string = function( s, prefix, pat )
if not s or #s == 0 then return "" end
pat = pat or ' '
local res = ''
local st = utils.string_to_table( s, pat )
utils.foreach( st, function( k, v ) res = res .. prefix .. v .. " " end )
return res
end
-- Like above but consider 'prefix' a path
utils.prepend_path = function( s, prefix, pat )
return utils.prepend_string( s, prefix .. dir_sep, pat )
end
-- full mkdir: create all the paths needed for a multipath
utils.full_mkdir = function( path )
local ptables = utils.string_to_table( path, dir_sep )
local p, res = ''
for i = 1, #ptables do
p = ( i ~= 1 and p .. dir_sep or p ) .. ptables[ i ]
res = lfs.mkdir( p )
end
return res
end
-- Concatenate the given paths to form a complete path
utils.concat_path = function( paths )
return table.concat( paths, dir_sep )
end
-- Return true if the given array contains the given element, false otherwise
utils.array_element_index = function( arr, element )
for i = 1, #arr do
if arr[ i ] == element then return i end
end
end
-- Linearize an array with (possibly) embedded arrays into a simple array
utils._linearize_array = function( arr, res )
if type( arr ) ~= "table" then return end
for i = 1, #arr do
local e = arr[ i ]
if type( e ) == 'table' then
utils._linearize_array( e, res )
else
table.insert( res, e )
end
end
end
utils.linearize_array = function( arr )
local res = {}
utils._linearize_array( arr, res )
return res
end
-- Return an array with the keys of a table
utils.table_keys = function( t )
local keys = {}
utils.foreach( t, function( k, v ) table.insert( keys, k ) end )
return keys
end
-- Returns true if 'path' is a regular file, false otherwise
utils.is_file = function( path )
return lfs.attributes( path, "mode" ) == "file"
end
-- Return a list of files in the given directory matching a given mask
utils.get_files = function( path, mask )
local t = ''
for f in lfs.dir( path ) do
local fname = path .. dir_sep .. f
if lfs.attributes( fname, "mode" ) == "file" and fname:find( mask ) then
t = t .. ' ' .. fname
end
end
return t
end
-- Check if the given command can be executed properly
utils.check_command = function( cmd )
local res = os.execute( cmd .. " > .build.temp 2>&1" )
os.remove( ".build.temp" )
return res
end
-- Execute the given command for each value in a table
utils.foreach = function ( t, cmd )
if type( t ) ~= "table" then return end
for k, v in pairs( t ) do cmd( k, v ) end
end
-------------------------------------------------------------------------------
-- Dummy 'builder': simply checks the date of a file
@ -250,7 +117,7 @@ _fbuilder.target_name = function( self )
end
-- Object type
_fbuilder.objtype = function()
_fbuilder.__type = function()
return "_fbuilder"
end
@ -264,29 +131,40 @@ _target.new = function( target, dep, command, builder )
setmetatable( self, { __index = _target } )
self.target = target
self.command = command
self:set_dependencies( dep )
self._force_rebuild = #self.dep == 0
self.builder = builder
builder.tlist[ target ] = self
builder:register_target( target, self )
self:set_dependencies( dep )
self.dep = self:_build_dependencies( self.origdep )
self._force_rebuild = #self.dep == 0
builder.runlist[ target ] = false
return self
end
-- Set dependencies
_target.set_dependencies = function( self, dep )
-- Transform 'dep' into a list of objects that support the 'build' method
if type( dep ) == 'string' then
dep = utils.string_to_table( dep )
elseif type( dep ) ~= 'table' then
dep = {}
self.origdep = dep
end
-- Set dependencies
-- This uses a proxy table and returns string deps dynamically according
-- to the targets currently registered in the builder
_target._build_dependencies = function( self, dep )
-- Step 1: start with an array
if type( dep ) == "string" then dep = utils.string_to_table( dep ) end
-- Step 2: linearize "dep" array keeping targets
local filter = function( e )
local t = exttype( e )
return t ~= "_ftarget" and t ~= "_target"
end
-- Iterate through 'dep' transforming file names in _fbuilder targets
dep = utils.linearize_array( dep, filter )
-- Step 3: strings are turned into _fbuilder objects if not found as targets;
-- otherwise the corresponding target object is used
for i = 1, #dep do
if type( dep[ i ] ) == "string" then
dep[ i ] = _fbuilder.new( self.target, dep[ i ] )
if type( dep[ i ] ) == 'string' then
local t = self.builder:get_registered_target( dep[ i ] )
dep[ i ] = t or _fbuilder.new( self.target, dep[ i ] )
end
end
self.dep = dep
return dep
end
-- Set pre-build function
@ -325,14 +203,15 @@ _target.build = function( self )
local docmd = self:target_name() and lfs.attributes( self:target_name(), "mode" ) ~= "file"
docmd = docmd or self.builder.global_force_rebuild
local initdocmd = docmd
local depends, dep = '', self.dep
self.dep = self:_build_dependencies( self.origdep )
local depends, dep, previnit = '', self.dep, self.origdep
-- Iterate through all dependencies, execute each one in turn
local deprunner = function()
for i = 1, #dep do
local res = dep[ i ]:build()
docmd = docmd or res
local t = dep[ i ]:target_name()
if dep[ i ]:objtype() == "_target" and t then
if exttype( dep[ i ] ) == "_target" and t then
docmd = docmd or get_ftime( t ) > get_ftime( self.target )
end
if t then depends = depends .. t .. " " end
@ -343,9 +222,10 @@ _target.build = function( self )
if self._pre_build_function then self._pre_build_function( self, docmd ) end
-- If the dependencies changed as a result of running the pre-build function
-- run through them again
if dep ~= self.dep then
depends, dep, docmd = '', self.dep, initdocmd
deprunner()
if previnit ~= self.origdep then
self.dep = self:_build_dependencies( self.origdep )
depends, dep, docmd = '', self.dep, initdocmd
deprunner()
end
-- If at least one dependency is new rebuild the target
docmd = docmd or self._force_rebuild or self.builder.clean_mode
@ -384,7 +264,7 @@ _target.target_name = function( self )
end
-- Object type
_target.objtype = function()
_target.__type = function()
return "_target"
end
@ -409,7 +289,7 @@ builder.new = function( build_dir )
self.build_mode = self.KEEP_DIR
self.targets = {}
self.targetargs = {}
self.tlist = {}
self._tlist = {}
self.runlist = {}
return self
end
@ -688,7 +568,7 @@ builder._compare_config = function( self, what )
local res = false
local crtstate = self:_config_to_string( what )
if not self.clean_mode then
local fconf = io.open( self.build_dir .. dir_sep .. ".builddata." .. what, "rb" )
local fconf = io.open( self.build_dir .. utils.dir_sep .. ".builddata." .. what, "rb" )
if fconf then
local oldstate = fconf:read( "*a" )
fconf:close()
@ -696,7 +576,7 @@ builder._compare_config = function( self, what )
end
end
-- Write state to build dir
fconf = io.open( self.build_dir .. dir_sep .. ".builddata." .. what, "wb" )
fconf = io.open( self.build_dir .. utils.dir_sep .. ".builddata." .. what, "wb" )
if fconf then
fconf:write( self:_config_to_string( what ) )
fconf:close()
@ -756,7 +636,7 @@ end
-- Return the name of a dependency file name corresponding to a C source
builder.get_dep_filename = function( self, srcname )
return utils.replace_extension( self.build_dir .. dir_sep .. linearize_fname( srcname ), "d" )
return utils.replace_extension( self.build_dir .. utils.dir_sep .. linearize_fname( srcname ), "d" )
end
-- Create a return a new C dependency target
@ -780,6 +660,19 @@ builder.target = function( self, dest_target, deps, cmd )
return _target.new( dest_target, deps, cmd, self )
end
-- Register a target (called from _target.new)
builder.register_target = function( self, name, obj )
self._tlist[ name:gsub( "\\", "/" ) ] = obj
end
-- Returns a registered target (nil if not found)
builder.get_registered_target = function( self, name )
return self._tlist[ name:gsub( "\\", "/" ) ]
end
---------------------------------------
-- Actual building functions
-- Return the object name corresponding to a source file name
builder.obj_name = function( self, name )
local r = self.obj_extension
@ -793,11 +686,11 @@ builder.obj_name = function( self, name )
if self.build_mode == self.KEEP_DIR then
return objname
elseif self.build_mode == self.BUILD_DIR_LINEARIZED then
return self.build_dir .. dir_sep .. linearize_fname( objname )
return self.build_dir .. utils.dir_sep .. linearize_fname( objname )
else
local si, ei, path, fname = objname:find( "(.+)/(.-)$" )
if not si then fname = objname end
return self.build_dir .. dir_sep .. fname
return self.build_dir .. utils.dir_sep .. fname
end
end
@ -866,9 +759,9 @@ builder.create_compile_targets = function( self, ftable, res )
local target
local deps = self:get_dep_filename( ftable[ i ] )
if ftable[ i ]:find( "%.c$" ) then
target = self:c_target( self:obj_name( ftable[ i ] ), { self.tlist[ deps ] or ftable[ i ] } )
target = self:c_target( self:obj_name( ftable[ i ] ), { self:get_registered_target( deps ) or ftable[ i ] } )
else
target = self:asm_target( self:obj_name( ftable[ i ] ), { self.tlist[ deps ] or ftable[ i ] } )
target = self:asm_target( self:obj_name( ftable[ i ] ), { self:get_registered_target( deps ) or ftable[ i ] } )
end
-- Post build step: replace dependencies with the ones generated by 'make_depends'
target:set_pre_build_function( function( t, _ )
@ -929,8 +822,8 @@ builder.build = function( self, target )
local res = self.targets[ t ].target:build()
if not res then print( sf( '[builder] %s: up to date', t ) ) end
if self.clean_mode then
os.remove( self.build_dir .. dir_sep .. ".builddata.comp" )
os.remove( self.build_dir .. dir_sep .. ".builddata.link" )
os.remove( self.build_dir .. utils.dir_sep .. ".builddata.comp" )
os.remove( self.build_dir .. utils.dir_sep .. ".builddata.link" )
end
print "[builder] Done building target."
return res

143
utils/utils.lua Normal file
View File

@ -0,0 +1,143 @@
-- Generic utility functions
module( ..., package.seeall )
local lfs = require "lfs"
local sf = string.format
-- Taken from Lake
dir_sep = package.config:sub( 1, 1 )
is_os_windows = dir_sep == '\\'
-- Converts a string with items separated by 'sep' into a table
string_to_table = function( s, sep )
if type( s ) ~= "string" then return end
sep = sep or ' '
if s:sub( -1, -1 ) ~= sep then s = s .. sep end
s = s:gsub( sf( "^%s*", sep ), "" )
local t = {}
local fmt = sf( "(.-)%s+", sep )
for w in s:gmatch( fmt ) do table.insert( t, w ) end
return t
end
-- Split a file name into 'path part' and 'extension part'
split_path = function( s )
local pos
for i = #s, 1, -1 do
if s:sub( i, i ) == "." then
pos = i
break
end
end
if pos then return s:sub( 1, pos - 1 ), s:sub( pos ) end
return s
end
-- Replace the extension of a give file name
replace_extension = function( s, newext )
local p, e = split_path( s )
if e then s = p .. "." .. newext end
return s
end
-- Return 'true' if building from Windows, false otherwise
is_windows = function()
return is_os_windows
end
-- Prepend each component of a 'pat'-separated string with 'prefix'
prepend_string = function( s, prefix, pat )
if not s or #s == 0 then return "" end
pat = pat or ' '
local res = ''
local st = string_to_table( s, pat )
foreach( st, function( k, v ) res = res .. prefix .. v .. " " end )
return res
end
-- Like above but consider 'prefix' a path
prepend_path = function( s, prefix, pat )
return prepend_string( s, prefix .. dir_sep, pat )
end
-- full mkdir: create all the paths needed for a multipath
full_mkdir = function( path )
local ptables = string_to_table( path, dir_sep )
local p, res = ''
for i = 1, #ptables do
p = ( i ~= 1 and p .. dir_sep or p ) .. ptables[ i ]
res = lfs.mkdir( p )
end
return res
end
-- Concatenate the given paths to form a complete path
concat_path = function( paths )
return table.concat( paths, dir_sep )
end
-- Return true if the given array contains the given element, false otherwise
array_element_index = function( arr, element )
for i = 1, #arr do
if arr[ i ] == element then return i end
end
end
-- Linearize an array with (possibly) embedded arrays into a simple array
_linearize_array = function( arr, res, filter )
if type( arr ) ~= "table" then return end
for i = 1, #arr do
local e = arr[ i ]
if type( e ) == 'table' and filter( e ) then
_linearize_array( e, res, filter )
else
table.insert( res, e )
end
end
end
linearize_array = function( arr, filter )
local res = {}
filter = filter or function( v ) return true end
_linearize_array( arr, res, filter )
return res
end
-- Return an array with the keys of a table
table_keys = function( t )
local keys = {}
foreach( t, function( k, v ) table.insert( keys, k ) end )
return keys
end
-- Returns true if 'path' is a regular file, false otherwise
is_file = function( path )
return lfs.attributes( path, "mode" ) == "file"
end
-- Return a list of files in the given directory matching a given mask
get_files = function( path, mask )
local t = ''
for f in lfs.dir( path ) do
local fname = path .. dir_sep .. f
if lfs.attributes( fname, "mode" ) == "file" and fname:find( mask ) then
t = t .. ' ' .. fname
end
end
return t
end
-- Check if the given command can be executed properly
check_command = function( cmd )
local res = os.execute( cmd .. " > .build.temp 2>&1" )
os.remove( ".build.temp" )
return res
end
-- Execute the given command for each value in a table
foreach = function ( t, cmd )
if type( t ) ~= "table" then return end
for k, v in pairs( t ) do cmd( k, v ) end
end