AbePralle-FGB/Tools/MapMaker/Build.rogue

386 lines
13 KiB
Plaintext
Raw Permalink Normal View History

# To run this build file, install Rogue from github.com/AbePralle/Rogue then cd
# to this folder and type "rogo" at the command line.
# description()s are optional - Rogo uses introspection to determine which
# commands are available. 'rogo help default' displays the description for
# "default", etc.
description( "default", "The default action is performed when no other actions are specified. Use 'rogo default' to explicitly perform the default option." )
description( "help", "Displays a list of all actions that can be performed by Rogo." )
#$ LIBRARIES(macOS) = libpng libjpeg zlib
#$ LIBRARIES(Linux-apt) = libpng-dev libjpeg-dev
augment Build
# You can create a Local.mk file with overrides for these values, e.g.:
# LAUNCHER_FOLDER = "~/bin"
PROPERTIES
PROJECT = "MapMaker"
LAUNCHER_NAME = "mapmaker"
LAUNCHER_FOLDER = "/usr/local/bin"
endAugment
routine exe_filepath->String
if (System.is_windows) return "Build/$.exe" (Build.LAUNCHER_NAME)
return "Build/$-$" (Build.PROJECT,System.os)
endRoutine
routine launcher_folder->String
local result = Build.LAUNCHER_FOLDER
result = File.expand_path( result )
return File.without_trailing_separator( result )
endRoutine
routine rogo_default
rogo_build
rogo_run
#rogo_install_launcher # Uncomment to automatically install a /usr/local/bin/mapmaker launcher
endRoutine
routine rogo_build
block exe_filepath
local source_files = Files( "Source", "**/*.rogue" )
local src_filepath = "Source/$.rogue" (Build.PROJECT)
if (source_files.any_newer_than(exe_filepath))
local cpp_filepath = "Build/$-$.cpp" (Build.PROJECT,System.os)
if (source_files.any_newer_than(cpp_filepath))
execute "roguec $ --main --output=$ --target=Console,C++,$" (src_filepath,cpp_filepath,System.os)
endIf
if (System.is_windows)
local libs = ""
local cc = "cl /EHsc /nologo $ /Fe$ $" (cpp_filepath,exe_filepath,libs)
#cc += " /link /LTCG" # uncomment this if there are errors linking libraries
execute cc
else
local libs = which{ System.is_linux:" $LIBRARY_FLAGS(libpng-dev,libjpeg-dev)" || " $LIBRARY_FLAGS(libpng,libjpeg,zlib)" }
local cc = "c++ -Wall -std=gnu++11 -fno-strict-aliasing -Wno-invalid-offsetof $ -o $$" (cpp_filepath,exe_filepath,libs)
execute cc
endIf
endIf
endBlock
endRoutine
routine rogo_run
execute File.conventional_filepath(exe_filepath)
endRoutine
routine rogo_install_launcher
local exe_filepath = File.absolute_filepath( exe_filepath )
if (System.is_windows)
local exe_folder = File.conventional_filepath( File.folder(exe_filepath) )
local path = System.environment//PATH
if (not path.to_lowercase.contains(exe_folder.to_lowercase))
println
println ''Add the following to your system PATH then reopen this command prompt to be able''
println ''to launch $ by typing "$":'' (Build.PROJECT,Build.LAUNCHER_NAME)
println
println " ADD THIS TO YOUR PATH"
println " " + exe_folder
endIf
else
contingent
local result = Process.run( "which " + Build.LAUNCHER_NAME, &env )
necessary (result.success)
local launcher_filepath = result->String.trimmed
necessary launcher_filepath
necessary File.load_as_string( launcher_filepath ).contains( exe_filepath )
unsatisfied
local launcher_filepath = "$/$" (launcher_folder,Build.LAUNCHER_NAME)
println "Creating launcher " + launcher_filepath
local sudo = ""
loop
try
if (not File.exists(launcher_folder)) execute( "$mkdir $"(sudo,launcher_folder) )
File.save( "$.launcher"(Build.LAUNCHER_NAME), ''#!/bin/sh\nexec "$" "$@"\n''(exe_filepath,'$') )
execute( "$mv $.launcher $"(sudo,Build.LAUNCHER_NAME,launcher_filepath) )
execute( "$chmod a+x $"(sudo,launcher_filepath) )
escapeLoop
catch (err:Error)
if (sudo != "") throw err
sudo = "sudo "
endTry
endLoop
endContingent
endIf
endRoutine
routine rogo_clean
verbose_delete( "Build" )
if (not System.is_windows) verbose_delete( "$/$"(launcher_folder,Build.LAUNCHER_NAME) )
endRoutine
routine verbose_delete( filepath:String )
if (File.exists(filepath))
println "> Delete " + filepath
if (not File.delete(filepath))
println "*** Failed to delete - retrying with sudo"
local cmd = ''sudo rm -rf $'' (File.shell_escaped(filepath))
execute cmd
endIf
endIf
endRoutine
routine execute( commands:String, &suppress_error )->Logical
forEach (cmd in LineReader(commands))
print( "> " ).println( cmd )
if (System.run(cmd) != 0)
if (suppress_error) return false
else throw Error( "Build failed." )
endIf
endForEach
return true
endRoutine
#-------------------------------------------------------------------------------
# Introspection-based Launcher Framework
#-------------------------------------------------------------------------------
# Rogo is a "build your own build system" facilitator. At its core Rogo just
# recompiles build files if needed and then runs the build executable while
# forwarding any command line arguments. This file contains a default framework
# which uses introspection to turn command line arguments into parameterized
# routine calls.
# Example: to handle the command "rogo abc xyz 5", define
# "routine rogo_abc_xyz( n:Int32 )".
# "rogo_default" will run in the absence of any other command line argument.
# The following "comment directives" can be used in this file to control how
# RogueC compiles it and to manage automatic dependency installation and
# linking.
# Each of the following should be on a line beginning with the characters #$
# (preceding whitespace is fine). Sample args are given.
# ROGUEC = roguec # Path to roguec to compile this file with
# ROGUEC_ARGS = --whatever # Additional options to pass to RogueC
# CPP = g++ -Wall -std=gnu++11 -fno-strict-aliasing
# -Wno-invalid-offsetof # C++ compiler path and/or invocation
# CPP_ARGS = -a -b -c # Additional C++ args
# LINK = true # Links following LIBRARIES with this Build
# # file (otherwise just installs them)
# LINK = -lalpha -lbeta # Links following LIBRARIES and includes
# # these additional flags
# LINK = false # Linking turned off for following
# # LIBRARIES - info can still be obtained
# # from $LIBRARY_FLAGS()
# LINK(macOS) = ... # Options applying only to
# # System.os=="macOS" (use with any OS and
# # any comment directive)
# LIBRARIES = libalpha
# LIBRARIES = libbeta(library-name)
# LIBRARIES = libfreetype6-dev(freetype2)
# DEPENDENCIES = Library/Rogue/**/*.rogue
#
# LIBRARIES = name(package)
# LIBRARIES = name(package:<package> install:<install-cmd>
# link:<link-flags> which:<which-name>)
#
# The following macro is replaced within this file (Build.rogue) - the libraries
# should normally also be declared in #$ LIBRARIES:
#
# $LIBRARY_FLAGS(lib1,lib2) # sample macro
# ->
# -Ipath/to/lib1/include -Lpath/to/lib1/library -I ... # sample replacement
routine syntax( command:String, text:String )
Build.rogo_syntax[ command ] = text
endRoutine
routine description( command:String, text:String )
Build.rogo_descriptions[ command ] = text
endRoutine
routine help( command:String, description=null:String, syntax=null:String )
if (description) Global.description( command, description )
if (syntax) Global.syntax( command, syntax )
endRoutine
try
Build.launch
catch (err:Error)
Build.rogo_error = err
Build.on_error
endTry
class Build [singleton]
PROPERTIES
rogo_syntax = StringTable<<String>>()
rogo_descriptions = StringTable<<String>>()
rogo_prefix = ?:{ $moduleName.count:$moduleName "::" || "" } + "rogo_" : String
rogo_command = "default"
rogo_args = @[]
rogo_error : Error
LOCAL_DEFS_FILE = "Local.mk"
METHODS
method launch
rogo_args.add( forEach in System.command_line_arguments )
read_defs
on_launch
parse_args
dispatch_command
method dispatch_command
local m = find_command( rogo_command )
require m || "no such routine rogo_$()" (rogo_command)
local args = @[]
forEach (arg in rogo_args)
which (arg)
case "true": args.add( true )
case "false": args.add( false )
case "null": args.add( NullValue )
others: args.add( arg )
endWhich
endForEach
if (m.parameter_count == 1 and args.count > 1) args = @[ args ] # Wrap args in a ValueList.
m( args )
method find_command( name:String )->MethodInfo
return <<Global>>.find_global_method( rogo_prefix + name )
method on_error
Console.error.println "=" * 79
Console.error.println rogo_error
Console.error.println "=" * 79
on_exit
System.exit 1
method on_command_found
noAction
method on_command_not_found
println "=" * 79
println "ERROR: No such command '$'." (rogo_args.first)
println "=" * 79
println
rogo_command = "help"
rogo_args.clear
on_command_found
method on_launch
noAction
method on_exit
noAction
method parse_args
block
if (rogo_args.count)
local parts = String[]
parts.add( forEach in rogo_args )
rogo_args.clear
while (parts.count)
local cmd = _join( parts )
if (find_command(cmd))
rogo_command = cmd
on_command_found
escapeBlock
endIf
rogo_args.insert( parts.remove_last )
endWhile
on_command_not_found
endIf
# Use default command
on_command_found
endBlock
method read_defs
read_defs( LOCAL_DEFS_FILE )
method read_defs( defs_filepath:String )
# Attempt to read defs from Local.mk
local overrides = String[]
if (File.exists(defs_filepath))
forEach (line in LineReader(File(defs_filepath)))
if (line.contains("="))
local name = line.before_first('=').trimmed
local value = line.after_first('=').trimmed
if (value.begins_with('"') or value.begins_with('\''))
value = value.leftmost(-1).rightmost(-1)
endIf
local p = <<Build>>.find_property( name )
if (p)
overrides.add( "$ = $" (name,value) )
<<Build>>.set_property( this, p, Value(value) )
endIf
endIf
endForEach
endIf
method _join( value:Value )->String
local args = String[]
args.add( forEach in value )
return args.join( "_" )
endClass
routine rogo_help( command="":String )
command = Build._join( Build.rogo_args )
if (command.count)
local syntax = get_syntax( command )
local success = false
if (syntax)
println "SYNTAX"
println " " + syntax
println
success = true
endIf
local description = get_description( command )
if (description)
println "DESCRIPTION"
forEach (line in LineReader(description.word_wrapped(76)))
print( " " ).println( line )
endForEach
println
success = true
endIf
if (success)
return
else
println "=" * 79
println "ERROR: No such command '$'." (command)
println "=" * 79
println
endIf
endIf
println "USAGE"
local lines = String[]
forEach (m in <<Global>>.global_methods)
if (m.name.begins_with(Build.rogo_prefix))
lines.add( " " + get_syntax(m.name.after_first(Build.rogo_prefix)) )
endIf
endForEach
lines.sort( (a,b)=>(a<b) )
println (forEach in lines)
println
endRoutine
routine get_syntax( m_name:String )->String
if (Build.rogo_syntax.contains(m_name))
return "rogo " + Build.rogo_syntax[ m_name ]
else
local m = <<Global>>.find_global_method( Build.rogo_prefix + m_name )
if (not m) return null
local line = "rogo $" (m_name.replacing('_',' '))
line += " <$>" (m.parameter_name(forEach in 0..<m.parameter_count))
return line
endIf
endRoutine
routine get_description( m_name:String )->String
if (Build.rogo_descriptions.contains(m_name))
return Build.rogo_descriptions[ m_name ]
else
return null
endIf
endRoutine