# To run this build file, install Rogue from github.com/AbePralle/Rogue and type "rogo" at the command line. #$ LIBRARIES(macOS) = rgbds( which:rgbasm ) # 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." ) augment Build PROPERTIES # These properties can be overridden with a Local.mk setting ROM_NAME=OtherName etc. ROM_NAME = "FGB.gb" endAugment routine rogo_default rogo_build endRoutine routine rogo_build local rgbasm = System.find_program( "rgbasm" ) if (not rgbasm) throw Error( "Please install the RGBDS Game Boy assembler from https://github.com/rednex/rgbds" ) endIf File.create_folder( "Build" ) File.create_folder( "ROM" ) local build_output = "Build/" + Build.ROM_NAME local rom_output = "ROM/" + Build.ROM_NAME local newest_datafile_timestamp = 0.0 forEach (datafile in File.listing("Data/**",&files,&ignore_hidden)) newest_datafile_timestamp = newest_datafile_timestamp.or_larger( File.timestamp(datafile) ) endForEach local obj_files = String[] local any_new_obj_files = false forEach (asm_file in File.listing("Source/**/*.asm")) local obj_file = "Build/$.obj" (File.filename(asm_file).leftmost(-4)) if (File.is_newer_than(asm_file,obj_file) or newest_datafile_timestamp > File.timestamp(obj_file)) execute "rgbasm -p 0xff $ -o $" (asm_file,obj_file) any_new_obj_files = true elseIf (File.is_newer_than(obj_file,rom_output)) any_new_obj_files = true endIf obj_files.add( obj_file ) endForEach if (any_new_obj_files) execute "rgblink --map Build/FGB.map --sym Build/FGB.sym $ -o $" (obj_files.join(" "),build_output) execute "rgbfix -p 0xff -v $" (build_output) local file_size = File.size( build_output ) println "> Copy $ -> $ ($ bytes)" (build_output,rom_output,file_size.format(",")) File.copy( build_output, rom_output ) else println "No changes detected. Output: $ ($ bytes)" (rom_output,File.size(rom_output).format(",")) endIf endRoutine routine rogo_clean verbose_delete( "Build" ) endRoutine routine verbose_delete( filepath:String ) if (File.exists(filepath)) println "> Delete " + filepath File.delete( filepath ) 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 compiler 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 # 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: install: link: which:) # # The following macro is replaced within this file (Build.rogue) - the libraries should 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<>() rogo_descriptions = StringTable<>() 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 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.call( Global, args ) method find_command( name:String )->MethodInfo return <>.find_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 = <>.find_property( name ) if (p) overrides.add( "$ = $" (name,value) ) <>.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 <>.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)=>(aString if (Build.rogo_syntax.contains(m_name)) return "rogo " + Build.rogo_syntax[ m_name ] else local m = <>.find_method( Build.rogo_prefix + m_name ) if (not m) return null local line = "rogo $" (m_name.replacing('_',' ')) line += " <$>" (m.parameter_name(forEach in 0..String if (Build.rogo_descriptions.contains(m_name)) return Build.rogo_descriptions[ m_name ] else return null endIf endRoutine