# 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_filepath( 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: install: # link: which:) # # 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<>() 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