Browse Source

Fixed conditional compiler processing. Fixes #22.
Added NX platform support.

woollybah 7 years ago
parent
commit
6b6ac721f2
8 changed files with 665 additions and 221 deletions
  1. 5 0
      CHANGELOG
  2. 9 0
      bmk.bmx
  3. 3 1
      bmk_config.bmx
  4. 91 8
      bmk_make.bmx
  5. 82 208
      bmk_modutil.bmx
  6. 170 1
      bmk_util.bmx
  7. 22 3
      make.bmk
  8. 283 0
      options_parser.bmx

+ 5 - 0
CHANGELOG

@@ -1,3 +1,8 @@
+## [3.27] - 2018-09-06
+### Fixed
+ - Fixed conditional compiler processing.
+### Added
+ - NX platform support.
 ## [3.26] - 2018-07-31
 ## [3.26] - 2018-07-31
 ### Fixed
 ### Fixed
  - Potential task race issue.
  - Potential task race issue.

+ 9 - 0
bmk.bmx

@@ -367,6 +367,10 @@ Function MakeApplication( args$[],makelib:Int,compileOnly:Int = False )
 	If processor.Platform() = "emscripten" Then
 	If processor.Platform() = "emscripten" Then
 		If ExtractExt(opt_outfile).ToLower()<>"html" opt_outfile:+".html"
 		If ExtractExt(opt_outfile).ToLower()<>"html" opt_outfile:+".html"
 	End If
 	End If
+
+	If processor.Platform() = "nx" Then
+		If ExtractExt(opt_outfile).ToLower()<>"elf" opt_outfile:+".elf"
+	End If
 	
 	
 	BeginMake
 	BeginMake
 	
 	
@@ -414,6 +418,11 @@ Rem
 		opt_outfile = previousOutfile
 		opt_outfile = previousOutfile
 	End If
 	End If
 End Rem
 End Rem
+
+	If processor.Platform() = "nx" And Not compileOnly Then
+		BuildNxDependencies()
+	End If
+
 	If opt_standalone And Not compileOnly
 	If opt_standalone And Not compileOnly
 		Local buildScript:String = String(globals.GetRawVar("EXEPATH")) + "/" + StripExt(StripDir( app_main )) + "." + opt_apptype + opt_configmung + processor.CPU() + ".build"
 		Local buildScript:String = String(globals.GetRawVar("EXEPATH")) + "/" + StripExt(StripDir( app_main )) + "." + opt_apptype + opt_configmung + processor.CPU() + ".build"
 		Local ldScript:String = "$APP_ROOT/ld." + processor.AppDet() + ".txt"
 		Local ldScript:String = "$APP_ROOT/ld." + processor.AppDet() + ".txt"

+ 3 - 1
bmk_config.bmx

@@ -10,7 +10,7 @@ Import brl.map
 
 
 Import "stringbuffer_core.bmx"
 Import "stringbuffer_core.bmx"
 
 
-Const BMK_VERSION:String = "3.26"
+Const BMK_VERSION:String = "3.27"
 
 
 Const ALL_SRC_EXTS$="bmx;i;c;m;h;cpp;cxx;mm;hpp;hxx;s;cc;asm;S"
 Const ALL_SRC_EXTS$="bmx;i;c;m;h;cpp;cxx;mm;hpp;hxx;s;cc;asm;S"
 
 
@@ -337,6 +337,7 @@ Function Usage:String(fullUsage:Int = False)
 		s:+ "~t~t~tAndroid : x86, x64, arm, armeabi, armeabiv7a, arm64v8a~n"
 		s:+ "~t~t~tAndroid : x86, x64, arm, armeabi, armeabiv7a, arm64v8a~n"
 		s:+ "~t~t~tRaspberryPi : arm, arm64~n"
 		s:+ "~t~t~tRaspberryPi : arm, arm64~n"
 		s:+ "~t~t~tEmscripten : js~n"
 		s:+ "~t~t~tEmscripten : js~n"
+		s:+ "~t~t~tnx : arm64~n"
 		s:+ "~n~n"
 		s:+ "~n~n"
 		s:+ "~t-gdb~n"
 		s:+ "~t-gdb~n"
 		s:+ "~t~tGenerates line mappings suitable for GDB debugging.~n"
 		s:+ "~t~tGenerates line mappings suitable for GDB debugging.~n"
@@ -594,6 +595,7 @@ Function ValidatePlatform(platform:String)
 		Case "android"
 		Case "android"
 		Case "raspberrypi"
 		Case "raspberrypi"
 		Case "emscripten"
 		Case "emscripten"
+		Case "nx"
 		Default
 		Default
 			' oops
 			' oops
 			CmdError "Not valid platform : '" + platform + "'"
 			CmdError "Not valid platform : '" + platform + "'"

+ 91 - 8
bmk_make.bmx

@@ -229,6 +229,83 @@ Function ConfigureIOSPaths()
 
 
 End Function
 End Function
 
 
+Function ConfigureNXPaths()
+	CheckNXPaths()
+	
+	Local toolchainBin:String
+	
+	Select processor.CPU()
+		Case "arm64"
+			toolchainBin = "aarch64-none-elf-"
+	End Select
+	
+	Local native:String
+?macos
+	native = "darwin"
+?linux
+	native = "linux"
+?win32
+	native = "windows"
+?
+
+	Local toolchainDir:String = processor.Option("nx.devkitpro", "") + "/devkitA64/"
+	
+	If FileType(toolchainDir) <> FILETYPE_DIR Then
+		Throw "Cannot determine toolchain dir for NX, at '" + toolchainDir + "'"
+	End If
+
+	Local exe:String	
+?win32
+	exe = ".exe"
+?
+	Local gccPath:String = toolchainDir + "/bin/" + toolchainBin + "gcc" + exe
+	Local gppPath:String = toolchainDir + "/bin/" + toolchainBin + "g++" + exe
+	Local arPath:String = toolchainDir + "/bin/" + toolchainBin + "ar" + exe
+	Local libPath:String = toolchainDir + "/lib"
+
+	' check paths
+	If Not FileType(RealPath(gccPath)) Then
+		Throw "gcc not found at '" + gccPath + "'"
+	End If
+
+	If Not FileType(RealPath(gppPath)) Then
+		Throw "g++ not found at '" + gppPath + "'"
+	End If
+
+	If Not FileType(RealPath(gccPath)) Then
+		Throw "ar not found at '" + arPath + "'"
+	End If
+	
+	globals.SetVar("nx." + processor.CPU() + ".gcc", gccPath)
+	globals.SetVar("nx." + processor.CPU() + ".gpp", gppPath)
+	globals.SetVar("nx." + processor.CPU() + ".ar", arPath)
+	globals.SetVar("nx." + processor.CPU() + ".lib", "-L" + libPath)
+
+?Not win32	
+	Local pathSeparator:String = ":"
+	Local dirSeparator:String = "/"
+?win32
+	Local pathSeparator:String = ";"
+	Local dirSeparator:String = "\"
+?
+	Local path:String = getenv_("PATH")
+	path = toolchainDir + dirSeparator + "bin" + pathSeparator + path
+	putenv_("PATH=" + path)
+
+End Function
+
+Function CheckNXPaths()
+	' check envs and paths
+	Local devkitpro:String = processor.Option("nx.devkitpro", getenv_("DEVKITPRO")).Trim()
+	If Not devkitpro Then
+		Throw "DEVKITPRO or 'nx.devkitpro' config option not set"
+	End If
+		
+	putenv_("DEVKITPRO=" + devkitpro)
+	globals.SetVar("nx.devkitpro", devkitpro)
+		
+End Function
+
 Type TBuildManager Extends TCallback
 Type TBuildManager Extends TCallback
 
 
 	Field sources:TMap = New TMap
 	Field sources:TMap = New TMap
@@ -244,6 +321,8 @@ Type TBuildManager Extends TCallback
 			ConfigureAndroidPaths()
 			ConfigureAndroidPaths()
 		Else If processor.Platform() = "ios" Then
 		Else If processor.Platform() = "ios" Then
 			ConfigureIOSPaths()
 			ConfigureIOSPaths()
+		Else If processor.Platform() = "nx" Then
+			ConfigureNXPaths()
 		End If
 		End If
 		
 		
 		processor.callback = Self
 		processor.callback = Self
@@ -636,7 +715,8 @@ Type TBuildManager Extends TCallback
 			' post process
 			' post process
 			LoadBMK(ExtractDir(app_main) + "/post.bmk")
 			LoadBMK(ExtractDir(app_main) + "/post.bmk")
 
 
-			If processor.Platform() = "android"
+			Select processor.Platform()
+			Case "android"
 				' create the apk
 				' create the apk
 				
 				
 				' copy shared object
 				' copy shared object
@@ -679,16 +759,19 @@ Type TBuildManager Extends TCallback
 				
 				
 				ChangeDir(dir)
 				ChangeDir(dir)
 		
 		
-			End If
-		
-		Else If processor.Platform() = "ios" Then
+			'End If
 		
 		
-			Local iosSimulator:Int = (processor.CPU() = "x86")
+			Case "ios"
 			
 			
-			' TODO - other stuff ?
+				Local iosSimulator:Int = (processor.CPU() = "x86")
+				
+				' TODO - other stuff ?
+			Case "nx"
 			
 			
+				' TODO - build nro, nso, psf0 and nacp
+				
+			End Select
 		End If
 		End If
-
 	End Method
 	End Method
 	
 	
 	Method CalculateDependencies(source:TSourceFile, isMod:Int = False, rebuildImports:Int = False, isInclude:Int = False)
 	Method CalculateDependencies(source:TSourceFile, isMod:Int = False, rebuildImports:Int = False, isInclude:Int = False)
@@ -1531,7 +1614,7 @@ Type TArcTask
 			Next
 			Next
 		End If
 		End If
 		
 		
-		If processor.Platform() = "linux" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "android" Or processor.Platform() = "emscripten"
+		If processor.Platform() = "linux" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "android" Or processor.Platform() = "emscripten" Or processor.Platform() = "nx"
 			For Local t$=EachIn oobjs
 			For Local t$=EachIn oobjs
 				If Len(cmd)+Len(t)>1000
 				If Len(cmd)+Len(t)>1000
 				
 				

+ 82 - 208
bmk_modutil.bmx

@@ -5,6 +5,7 @@ Import BRL.MaxUtil
 Import BRL.TextStream
 Import BRL.TextStream
 
 
 Import "bmk_util.bmx"
 Import "bmk_util.bmx"
+Import "options_parser.bmx"
 
 
 Const SOURCE_UNKNOWN:Int = 0
 Const SOURCE_UNKNOWN:Int = 0
 Const SOURCE_BMX:Int = $01
 Const SOURCE_BMX:Int = $01
@@ -448,6 +449,8 @@ Function ParseSourceFile:TSourceFile( path$ )
 
 
 	Local pos,in_rem,cc=True
 	Local pos,in_rem,cc=True
 
 
+	SetCompilerValues()
+	
 	While pos<Len(str)
 	While pos<Len(str)
 
 
 		Local eol=str.Find( "~n",pos )
 		Local eol=str.Find( "~n",pos )
@@ -482,214 +485,10 @@ Function ParseSourceFile:TSourceFile( path$ )
 				Continue
 				Continue
 			EndIf
 			EndIf
 
 
-			If lline[..1]="?"
-				Local t$=lline[1..].Trim()
-				
-				Local cNot
-				If t.StartsWith( "not " )
-					cNot=True
-					t=t[4..].Trim()
-				EndIf
-
-				t = t.toLower()
-				Select t
-				Case ""
-					cc=True
-				Case "debug"
-					cc=opt_debug
-				Case "threaded"
-					cc=opt_threaded
-'?x86
-				Case "x86" cc=processor.CPU()="x86"
-'?ppc
-				Case "ppc" cc=processor.CPU()="ppc"
-				Case "x64" cc=processor.CPU()="x64"
-				Case "arm" cc=processor.CPU()="arm"
-				Case "armeabi" cc=processor.CPU()="armeabi"
-				Case "armeabiv7a" cc=processor.CPU()="armeabiv7a"
-				Case "arm64v8a" cc=processor.CPU()="arm64v8a"
-				Case "armv7" cc=processor.CPU()="armv7"
-				Case "arm64" cc=processor.CPU()="arm64"
-				Case "js" cc=processor.CPU()="js"
-
-				Case "ptr32" cc=(processor.CPU()="x86" Or processor.CPU()="ppc" Or processor.CPU()="arm" Or processor.CPU()="armeabi" Or processor.CPU()="armeabiv7a" Or processor.CPU()="armv7" Or processor.CPU()="js")
-				Case "ptr64" cc=(processor.CPU()="x64" Or processor.CPU()="arm64v8a" Or processor.CPU()="arm64")
-''?
-				Case "win32" 
-					cc=False
-					If processor.Platform() = "win32"
-						cc=True
-					End If
-				Case "win32x86"
-					cc=False
-					If processor.Platform() = "win32"
-						cc=processor.CPU()="x86"
-					End If
-				Case "win32ppc"
-					cc=False
-					If processor.Platform() = "win32"
-						cc=processor.CPU()="ppc"
-					End If
-				Case "win32x64"
-					cc=False
-					If processor.Platform() = "win32"
-						cc=processor.CPU()="x64"
-					End If
-				Case "linux"
-					cc=False
-					If processor.Platform() = "linux" Or processor.Platform() = "android" Or processor.Platform() = "raspberrypi"
-						 cc=True
-					End If
-				Case "linuxx86"
-					cc=False
-					If processor.Platform() = "linux" Or processor.Platform() = "android"
-						 cc=processor.CPU()="x86"
-					End If
-				Case "linuxppc"
-					cc=False
-					If processor.Platform() = "linux"
-						 cc=processor.CPU()="ppc"
-					End If
-				Case "linuxx64"
-					cc=False
-					If processor.Platform() = "linux" Or processor.Platform() = "android"
-						 cc=processor.CPU()="x64"
-					End If
-				Case "linuxarm"
-					cc=False
-					If processor.Platform() = "linux" Or processor.Platform() = "android" Or processor.Platform() = "raspberrypi"
-						 cc=processor.CPU()="arm"
-					End If
-				Case "macos"
-					cc=False
-					If processor.Platform() = "macos" Or processor.Platform() = "osx" Or processor.Platform() = "ios"
-						cc=True
-					End If
-				Case "macosx86"
-					cc=False
-					If processor.Platform() = "macos"Or processor.Platform() = "osx" Or processor.Platform() = "ios"
-						 cc=processor.CPU()="x86"
-					End If
-				Case "macosppc"
-					cc=False
-					If processor.Platform() = "macos" Or processor.Platform() = "osx"
-						 cc=processor.CPU()="ppc"
-					End If
-				Case "macosx64"
-					cc=False
-					If processor.Platform() = "macos" Or processor.Platform() = "osx" Or processor.Platform() = "ios"
-						 cc=processor.CPU()="x64"
-					End If
-				Case "osx"
-					cc=False
-					If processor.Platform() = "macos" Or processor.Platform() = "osx"
-						cc=True
-					End If
-				Case "osxx86"
-					cc=False
-					If processor.Platform() = "macos"Or processor.Platform() = "osx"
-						 cc=processor.CPU()="x86"
-					End If
-				Case "osxx64"
-					cc=False
-					If processor.Platform() = "macos" Or processor.Platform() = "osx"
-						 cc=processor.CPU()="x64"
-					End If
-				Case "ios"
-					cc=False
-					If processor.Platform() = "ios"
-						cc=True
-					End If
-				Case "iosx86"
-					cc=False
-					If processor.Platform() = "ios"
-						 cc=processor.CPU()="x86"
-					End If
-				Case "iosx64"
-					cc=False
-					If processor.Platform() = "ios"
-						 cc=processor.CPU()="x64"
-					End If
-				Case "iosarmv7"
-					cc=False
-					If processor.Platform() = "ios"
-						 cc=processor.CPU()="armv7"
-					End If
-				Case "iosarm64"
-					cc=False
-					If processor.Platform() = "ios"
-						 cc=processor.CPU()="arm64"
-					End If
-				Case "android"
-					cc=False
-					If processor.Platform() = "android"
-						 cc=True
-					End If
-				Case "androidarm"
-					cc=False
-					If processor.Platform() = "android"
-						 cc=processor.CPU()="arm"
-					End If
-				Case "androidarmeabi"
-					cc=False
-					If processor.Platform() = "android"
-						 cc=processor.CPU()="armeabi"
-					End If
-				Case "androidarmeabiv7a"
-					cc=False
-					If processor.Platform() = "android"
-						 cc=processor.CPU()="armeabiv7a"
-					End If
-				Case "androidarm64v8a"
-					cc=False
-					If processor.Platform() = "android"
-						 cc=processor.CPU()="arm64v8a"
-					End If
-				Case "raspberrypi"
-					cc=False
-					If processor.Platform() = "raspberrypi"
-						 cc=True
-					End If
-				Case "raspberrypiarm"
-					cc=False
-					If processor.Platform() = "raspberrypi"
-						 cc=processor.CPU()="arm"
-					End If
-				Case "raspberrypiarm64"
-					cc=False
-					If processor.Platform() = "raspberrypi"
-						 cc=processor.CPU()="arm64"
-					End If
-				Case "emscripten"
-					cc=False
-					If processor.Platform() = "emscripten"
-						 cc=True
-					End If
-				Case "emscriptenjs"
-					cc=False
-					If processor.Platform() = "emscripten"
-						 cc=processor.CPU()="js"
-					End If
-				Case "opengles"
-					cc=False
-					If processor.Platform() = "android" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "emscripten" Or processor.Platform() = "ios" 
-						 cc=True
-					End If
-				Case "bmxng"
-					cc=False
-					If processor.BCCVersion() <> "BlitzMax" Then
-						cc=True
-					End If
-				Case "musl"
-					cc=False
-					If processor.Platform() = "linux" Or processor.Platform() ="raspberrypi"
-						 cc=True
-					End If
-				Default
-					cc=False
-				End Select
-				If cNot cc=Not cc
-				Continue
+			Local cmopt:String = lline.Trim()
+			If cmopt[..1]="?"
+				Local t$=cmopt[1..]
+				cc = EvalOption(t)
 			EndIf
 			EndIf
 
 
 			If Not cc Continue
 			If Not cc Continue
@@ -866,9 +665,84 @@ Function ValidatePlatformArchitecture()
 			If arch = "js" Then
 			If arch = "js" Then
 				valid = True
 				valid = True
 			End If
 			End If
+		Case "nx"
+			If arch = "arm64" Then
+				valid = True
+			End If
 	End Select
 	End Select
 	
 	
 	If Not valid Then
 	If Not valid Then
 		CmdError "Invalid Platform/Architecture configuration : " + platform + "/" + arch
 		CmdError "Invalid Platform/Architecture configuration : " + platform + "/" + arch
 	End If
 	End If
 End Function
 End Function
+
+Function SetCompilerValues()
+
+	compilerOptions = New TValues
+
+	compilerOptions.Add("debug", opt_debug)
+	compilerOptions.Add("threaded", opt_threaded)
+
+	compilerOptions.Add("x86", processor.CPU()="x86")
+
+	compilerOptions.Add("ppc", processor.CPU()="ppc")
+	compilerOptions.Add("x64", processor.CPU()="x64")
+	compilerOptions.Add("arm", processor.CPU()="arm")
+	compilerOptions.Add("armeabi", processor.CPU()="armeabi")
+	compilerOptions.Add("armeabiv7a", processor.CPU()="armeabiv7a")
+	compilerOptions.Add("arm64v8a", processor.CPU()="arm64v8a")
+	compilerOptions.Add("armv7", processor.CPU()="armv7")
+	compilerOptions.Add("arm64", processor.CPU()="arm64")
+	compilerOptions.Add("js", processor.CPU()="js")
+
+	compilerOptions.Add("ptr32", processor.CPU()="x86" Or processor.CPU()="ppc" Or processor.CPU()="arm" Or processor.CPU()="armeabi" Or processor.CPU()="armeabiv7a" Or processor.CPU()="armv7" Or processor.CPU()="js")
+	compilerOptions.Add("ptr64", processor.CPU()="x64" Or processor.CPU()="arm64v8a" Or processor.CPU()="arm64")
+
+	compilerOptions.Add("win32", processor.Platform() = "win32")
+	compilerOptions.Add("win32x86", processor.Platform() = "win32" And processor.CPU()="x86")
+	compilerOptions.Add("win32ppc", processor.Platform() = "win32" And processor.CPU()="ppc")
+	compilerOptions.Add("win32x64", processor.Platform() = "win32" And processor.CPU()="x64")
+
+	compilerOptions.Add("linux", processor.Platform() = "linux" Or processor.Platform() = "android" Or processor.Platform() = "raspberrypi")
+	compilerOptions.Add("linuxx86", (processor.Platform() = "linux" Or processor.Platform() = "android") And processor.CPU()="x86")
+	compilerOptions.Add("linuxppc", processor.Platform() = "linux" And processor.CPU()="ppc")
+	compilerOptions.Add("linuxx64", (processor.Platform() = "linux" Or processor.Platform() = "android") And processor.CPU()="x64")
+	compilerOptions.Add("linuxarm", (processor.Platform() = "linux" Or processor.Platform() = "android" Or processor.Platform() = "raspberrypi") And processor.CPU()="arm")
+
+	compilerOptions.Add("macos", processor.Platform() = "macos" Or processor.Platform() = "osx" Or processor.Platform() = "ios")
+	compilerOptions.Add("macosx86", (processor.Platform() = "macos"Or processor.Platform() = "osx" Or processor.Platform() = "ios") And processor.CPU()="x86")
+	compilerOptions.Add("macosppc", (processor.Platform() = "macos" Or processor.Platform() = "osx") And processor.CPU()="ppc")
+	compilerOptions.Add("macosx64", (processor.Platform() = "macos" Or processor.Platform() = "osx" Or processor.Platform() = "ios") And processor.CPU()="x64")
+	compilerOptions.Add("osx", processor.Platform() = "macos" Or processor.Platform() = "osx")
+	compilerOptions.Add("osxx86", (processor.Platform() = "macos"Or processor.Platform() = "osx") And processor.CPU()="x86")
+	compilerOptions.Add("osxx64", (processor.Platform() = "macos" Or processor.Platform() = "osx") And processor.CPU()="x64")
+	compilerOptions.Add("ios", processor.Platform() = "ios")
+	compilerOptions.Add("iosx86", processor.Platform() = "ios" And processor.CPU()="x86")
+	compilerOptions.Add("iosx64", processor.Platform() = "ios" And processor.CPU()="x64")
+	compilerOptions.Add("iosarmv7", processor.Platform() = "ios" And processor.CPU()="armv7")
+	compilerOptions.Add("iosarm64", processor.Platform() = "ios" And processor.CPU()="arm64")
+
+	compilerOptions.Add("android", processor.Platform() = "android")
+	compilerOptions.Add("androidarm", processor.Platform() = "android" And processor.CPU()="arm")
+	compilerOptions.Add("androidarmeabi", processor.Platform() = "android" And processor.CPU()="armeabi")
+	compilerOptions.Add("androidarmeabiv7a", processor.Platform() = "android" And processor.CPU()="armeabiv7a")
+	compilerOptions.Add("androidarm64v8a", processor.Platform() = "android" And processor.CPU()="arm64v8a")
+
+	compilerOptions.Add("raspberrypi", processor.Platform() = "raspberrypi")
+	compilerOptions.Add("raspberrypiarm", processor.Platform() = "raspberrypi" And processor.CPU()="arm")
+	compilerOptions.Add("raspberrypiarm64", processor.Platform() = "raspberrypi" And processor.CPU()="arm64")
+	
+	compilerOptions.Add("emscripten", processor.Platform() = "emscripten")
+	compilerOptions.Add("emscriptenjs", processor.Platform() = "emscripten" And processor.CPU()="js")
+
+	compilerOptions.Add("opengles", processor.Platform() = "android" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "emscripten" Or processor.Platform() = "ios")
+
+	compilerOptions.Add("bmxng", processor.BCCVersion() <> "BlitzMax")
+
+	compilerOptions.Add("musl", processor.Platform() = "linux" Or processor.Platform() ="raspberrypi")
+
+	compilerOptions.Add("nx", processor.Platform() = "nx")
+	compilerOptions.Add("nxarm64", processor.Platform() = "nx" And processor.CPU()="arm64")
+
+End Function
+

+ 170 - 1
bmk_util.bmx

@@ -54,7 +54,21 @@ Type TModOpt ' BaH
 	End Method
 	End Method
 
 
 	Function setPath:String(value:String, path:String)
 	Function setPath:String(value:String, path:String)
-		Return value.Replace("%PWD%", path)
+		If value.Contains("%PWD%") Then
+			Return value.Replace("%PWD%", path)
+		End If
+		
+		' var replace
+		Local s:Int = value.Find("%")
+		If s >= 0 Then
+			Local e:Int = value.Find("%", s + 1)
+			If e >= 0 Then
+				Local v:String = value[s+1..e]
+				value = value[..s] + processor.option(v, "NA") + value[e+1..]
+			End If
+		End If
+		
+		Return value
 	End Function
 	End Function
 	
 	
 End Type
 End Type
@@ -495,6 +509,44 @@ Function LinkApp( path$,lnk_files:TList,makelib,opts$ )
 		fb.Insert(0,"INPUT(").Append(")")
 		fb.Insert(0,"INPUT(").Append(")")
 	End If
 	End If
 	
 	
+	If processor.Platform() = "nx" Then
+		sb.Append(processor.Option(processor.BuildName("gpp"), "g++"))
+		
+		Local libso:String = StripDir(path)
+		sb.Append(" -MMD -MP -MF ")
+		sb.Append(" -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE ")
+		
+		sb.Append(" -specs=").Append(processor.Option("nx.devkitpro", "")).Append("/libnx/switch.specs")
+		sb.Append(" -g")
+		'sb.Append(" -Wl,-Map,").Append(StripExt(path)).Append(".map")
+		
+		sb.Append(" -L").Append(NXLibDir())
+	
+		sb.Append(" -o ").Append(CQuote( path ))
+		sb.Append(" ").Append(CQuote( tmpfile ))
+		
+		Local endLinks:TList = New TList
+		
+		For Local t$=EachIn lnk_files
+			t=CQuote(t)
+			If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l")
+				sb.Append(" ").Append(t)
+			Else
+				If t.Contains("appstub") Or t.Contains("blitz.mod") Then
+					endLinks.AddLast(t)
+					Continue
+				End If
+				fb.Append(" ").Append(t)
+			EndIf
+		Next
+
+		fb.Append(" -lnx -lm")
+		For Local t:String = EachIn endLinks
+			fb.Append(" ").Append(t)
+		Next
+
+		fb.Insert(0,"INPUT(").Append(")")
+	End If
 
 
 	Local t$=getenv_( "BMK_LD_OPTS" )
 	Local t$=getenv_( "BMK_LD_OPTS" )
 	If t 
 	If t 
@@ -760,6 +812,123 @@ Function GetAndroidSDKTarget:String()
 	
 	
 End Function
 End Function
 
 
+Function NXLibDir:String()
+	Return processor.Option("nx.devkitpro", "") + "/libnx/lib"
+End Function
+
+Function NxToolsDir:String()
+	Return processor.Option("nx.devkitpro", "") + "/tools/bin"
+End Function
+
+Function BuildNxDependencies()
+	
+	BuildNxNso()
+	BuildNxNacp()
+	BuildNxNro()
+	
+End Function
+
+Function BuildNxNso()
+
+	If Not opt_quiet Print "Building:" + StripDir(StripExt(opt_outfile)) + ".nso"
+
+	Local elf2nso:String = NxToolsDir() + "/elf2nso"
+?win32
+	elf2nso :+ ".exe"
+?
+	If Not FileType(elf2nso) Then
+		Throw "elf2nso tool not present at " + elf2nso
+	End If
+
+	Local app:String = StripExt(opt_outfile)
+	
+	Local cmd:String = elf2nso + " " + CQuote(app + ".elf")
+	cmd :+ " " + CQuote(app + ".nso")
+	
+	Sys(cmd)
+End Function
+
+Function BuildNxNacp()
+
+	If Not opt_quiet Print "Building:" + StripDir(StripExt(opt_outfile)) + ".nacp"
+
+	Local nacptool:String = NxToolsDir() + "/nacptool"
+?win32
+	nacptool :+ ".exe"
+?
+	If Not FileType(nacptool) Then
+		Throw "nacptool tool not present at " + nacptool
+	End If
+
+	Local app:String = StripExt(opt_outfile)
+	
+	Local cmd:String = nacptool + " --create"
+	Local name:String = processor.AppSetting("app.name")
+	If Not name Then
+		name = StripDir(StripExt(opt_outfile))
+	End If
+	cmd :+ " " + CQuote(name)
+	
+	Local auth:String = processor.AppSetting("app.company")
+	If Not auth Then
+		auth = "Unspecified Author"
+	End If
+	cmd :+ " " + CQuote(auth)
+	
+	Local ver:String = processor.AppSetting("app.version.name")
+	If Not ver Then
+		ver = "1.0.0"
+	End If
+	cmd :+ " " + CQuote(ver)
+	
+	cmd :+ " " + CQuote(app + ".nacp")
+
+	Sys(cmd)
+End Function
+
+Function BuildNxNro()
+
+	If Not opt_quiet Print "Building:" + StripDir(StripExt(opt_outfile)) + ".nro"
+
+	Local elf2nro:String = NxToolsDir() + "/elf2nro"
+?win32
+	elf2nro :+ ".exe"
+?
+
+	If Not FileType(elf2nro) Then
+		Throw "elf2nro tool not present at " + elf2nro
+	End If
+
+	' get icon
+	Local icon:String
+	' app.jpg
+	' TODO
+	' icon.jpg
+	' TODO
+	' default icon
+	If Not icon Then
+		icon = processor.Option("nx.devkitpro", "") + "/libnx/default_icon.jpg"
+		If Not FileType(icon) Then
+			Throw "Default icon not found at " + icon
+		End If
+	End If
+	
+	Local app:String = StripExt(opt_outfile)
+	
+	Local cmd:String = elf2nro + " " + CQuote(app + ".elf")
+	cmd :+ " " + CQuote(app + ".nro")
+	cmd :+ " --icon=" + CQuote(icon)
+	cmd :+ " --nacp=" + CQuote(app + ".nacp")
+	
+	Local romfsDir:String = ExtractDir(opt_outfile) + "/romfs"
+	
+	If FileType(romfsDir) = FILETYPE_DIR Then
+		cmd :+ " --romfsdir=" + CQuote(romfsDir)
+	End If
+	
+	Sys(cmd)	
+End Function
+
 Function PathFromPackage:String(package:String)
 Function PathFromPackage:String(package:String)
 	Return package.Replace(".", "/")
 	Return package.Replace(".", "/")
 End Function
 End Function

+ 22 - 3
make.bmk

@@ -151,7 +151,7 @@
 			cmd = bmk.Option(bmk.BuildName("gcc"), "gcc")
 			cmd = bmk.Option(bmk.BuildName("gcc"), "gcc")
 			
 			
 			if ext == "cpp" or ext == "cxx" or ext == "mm" or ext == "cc" then
 			if ext == "cpp" or ext == "cxx" or ext == "mm" or ext == "cc" then
-				cmd = bmk.Option(bmk.BuildName("g++"), "g++")
+				cmd = bmk.Option(bmk.BuildName("gpp"), "g++")
 			end
 			end
 		end
 		end
 		
 		
@@ -190,15 +190,30 @@
 		cmd = bmk.Option(bmk.BuildName("gcc"), "emcc")
 		cmd = bmk.Option(bmk.BuildName("gcc"), "emcc")
 		
 		
 		cmd = cmd .. " -Wno-warn-absolute-paths "
 		cmd = cmd .. " -Wno-warn-absolute-paths "
+	elseif bmk.Platform() == "nx" then
+		cmd = bmk.Option(bmk.BuildName("gcc"), "gcc")
+		if ext == "cpp" or ext == "cxx" or ext == "mm" or ext == "cc" then
+			cmd = bmk.Option(bmk.BuildName("gpp"), "g++")
+		end
 	end
 	end
 
 
+	if bmk.Platform() == "nx" then
+		cmd = cmd .. " -ffunction-sections"
+		cmd = cmd .. " -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE"
+		cmd = cmd .. " -I" .. bmk.Option("nx.devkitpro", "") .. "/libnx/include"
+		cmd = cmd .. " -I" .. bmk.Option("nx.devkitpro", "")
+	end
+	
 	# disable warnings ?
 	# disable warnings ?
 	if %CC_WARNINGS% == "" then
 	if %CC_WARNINGS% == "" then
 		opts = opts .. " -w"
 		opts = opts .. " -w"
 	end
 	end
-	
+
 	if bmk.BCCVersion() ~= "BlitzMax" then
 	if bmk.BCCVersion() ~= "BlitzMax" then
 		opts = opts .. " -DBMX_NG"
 		opts = opts .. " -DBMX_NG"
+		if bmk.Platform() == "nx" then
+			opts = opts .. " -D__SWITCH__"
+		end
 	end
 	end
 	
 	
 	local genDebug = ""
 	local genDebug = ""
@@ -459,7 +474,11 @@
 
 
 	globals.SetOption("cc_opts", "exceptions", "-fno-exceptions")
 	globals.SetOption("cc_opts", "exceptions", "-fno-exceptions")
 	globals.SetOption("cc_opts", "linker", "-c")
 	globals.SetOption("cc_opts", "linker", "-c")
-	globals.SetOption("cc_opts", "optimization", "-O3")
+	if bmk.Platform() ~= "nx" then
+		globals.SetOption("cc_opts", "optimization", "-O3")
+	else
+		globals.SetOption("cc_opts", "optimization", "-O2")
+	end
 	if bmk.CPU() == "x64" then
 	if bmk.CPU() == "x64" then
 		globals.SetOption("cc_opts", "simd", "-msse3")
 		globals.SetOption("cc_opts", "simd", "-msse3")
 	end
 	end

+ 283 - 0
options_parser.bmx

@@ -0,0 +1,283 @@
+SuperStrict
+
+Import brl.map
+Import "stringbuffer_core.bmx"
+
+Global compilerOptions:TValues
+
+Function EvalOption:Int(line:String)
+	If Not line Then
+		Return True
+	End If
+	Local tok:TOptTokenizer = New TOptTokenizer.Create(line.ToLower())
+	Local parser:TOptParser = New TOptParser.Create(tok, compilerOptions)
+	Return parser.Eval()
+End Function
+
+Type TOptParser
+
+	Field tokenizer:TOptTokenizer
+	Field token:TOptToken
+	
+	Field values:TValues
+	
+	Method Create:TOptParser(tokenizer:TOptTokenizer, values:TValues)
+		Self.tokenizer = tokenizer
+		Self.values = values
+		Return Self
+	End Method
+
+	Method Eval:Int()
+		NextToke
+		Local expr:TExpr = Parse()
+		Return expr.Eval()
+	End Method
+
+	Method NextToke()
+		token = tokenizer.NextToken()
+	End Method
+
+	Method Parse:TExpr()
+		Return ParseOrExpr()
+	End Method
+	
+	Method ParseOrExpr:TExpr()
+		Local expr:TExpr = ParseAndExpr()
+		Repeat
+			If token.tokType = TOK_OR Then
+				NextToke
+				Local rhs:TExpr = ParseAndExpr()
+				expr = New TBinaryExpr.Create(TOK_OR, expr, rhs)
+			Else
+				Return expr
+			End If
+		Forever
+		Return expr
+	End Method
+	
+	Method ParseAndExpr:TExpr()
+		Local expr:TExpr = ParseNotExpr()
+		Repeat
+			If token.tokType = TOK_AND Then
+				NextToke
+				Local rhs:TExpr = ParseNotExpr()
+				expr = New TBinaryExpr.Create(TOK_AND, expr, rhs)
+			Else
+				Return expr
+			End If
+		Forever
+	End Method
+	
+	Method ParseNotExpr:TExpr()
+		If token.tokType = TOK_NOT Then
+			NextToke
+			Local expr:TExpr = ParseNotExpr()
+			Return New TNotExpr.Create(expr)
+		End If
+		
+		Return ParsePrimaryExpr()
+	End Method
+	
+	Method ParsePrimaryExpr:TExpr()
+		Local expr:TExpr
+		
+		Select token.tokType
+			Case TOK_LPAREN
+				NextToke
+				expr = Parse()
+				If token.tokType <> TOK_RPAREN Then
+					Throw "Expected ')'"
+				End If
+			Case TOK_IDENT
+				Local value:Int = values.Value(token.value)
+				expr = New TIdentExpr.Create(token.value, value)
+				NextToke
+			Case TOK_RPAREN
+				Throw "Unexpected ')'"
+		End Select
+		
+		Return expr
+	End Method
+	
+End Type
+
+Type TOptToken
+
+	Field tokType:Int
+	Field value:String
+	
+	Method Create:TOptToken(tokType:Int, value:String)
+		Self.tokType = tokType
+		Self.value = value
+		Return Self
+	End Method
+	
+End Type
+
+Type TOptTokenizer
+	
+	Field line:String
+	Field pos:Int
+
+	Method Create:TOptTokenizer(line:String)
+		Self.line = line
+		Return Self
+	End Method
+
+	Method NextToken:TOptToken()
+		While True
+			If pos = line.length
+				Return New TOptToken.Create(TOK_EOL, Null)
+			End If
+			
+			Local char:Int = line[pos]
+			
+			pos :+ 1
+			
+			If char = Asc("(") Then
+				Return New TOptToken.Create(TOK_LPAREN, "(")
+			Else If char = Asc(")") Then
+				Return New TOptToken.Create(TOK_RPAREN, ")")
+			Else If IsAlphaNumeric(char) Then
+				Return NextIdentToken(char)
+			Else If Not IsWhitespace(char) Then
+				Throw "Unexpected character : " + Chr(char)
+			End If			
+		Wend
+	End Method
+	
+	Method NextIdentToken:TOptToken(char:Int)
+		Local sb:TStringBuffer = TStringBuffer.Create(Chr(char))
+		
+		While True
+			char = Peek()
+			If Not IsAlphaNumeric(char) Then
+				Exit
+			End If
+			
+			pos :+ 1
+			sb.Append(Chr(char))
+		Wend
+		
+		Local token:String = sb.ToString().ToLower()
+		
+		Select token
+			Case "not"
+				Return New TOptToken.Create(TOK_NOT, token)
+			Case "and"
+				Return New TOptToken.Create(TOK_AND, token)
+			Case "or"
+				Return New TOptToken.Create(TOK_OR, token)
+			Default
+				Return New TOptToken.Create(TOK_IDENT, token)
+		End Select
+	End Method
+	
+	Method IsAlphaNumeric:Int(char:Int)
+		Return (char >= Asc("A") And char <= Asc("Z")) Or (char >= Asc("a") And char <= Asc("z")) Or (char >= Asc("0") And char <= Asc("9"))
+	End Method
+	
+	Method IsWhitespace:Int(char:Int)
+		Return char = Asc(" ") Or char = Asc("~t")
+	End Method
+	
+	Method Peek:Int()
+		If pos < line.length Then
+			Return line[pos]
+		End If
+		
+		Return 0
+	End Method
+	
+End Type
+
+Type TExpr
+	Method Eval:Int() Abstract
+End Type
+
+Type TNotExpr Extends TExpr
+	Field expr:TExpr
+	
+	Method Create:TNotExpr(expr:TExpr)
+		Self.expr = expr
+		Return Self
+	End Method
+	
+	Method Eval:Int()
+		Return Not expr.Eval()
+	End Method
+	
+End Type
+
+Type TBinaryExpr Extends TExpr
+	Field op:Int
+	Field lhs:TExpr
+	Field rhs:TExpr
+
+	Method Create:TBinaryExpr(op:Int, lhs:TExpr, rhs:TExpr)
+		Self.op = op
+		Self.rhs = rhs
+		Self.lhs = lhs
+		Return Self
+	End Method
+	
+	Method Eval:Int()
+		Select op
+			Case TOK_OR
+				Return lhs.Eval() Or rhs.Eval()
+			Case TOK_AND
+				Return lhs.Eval() And rhs.Eval()
+		End Select
+	End Method
+	
+End Type
+
+Type TIdentExpr Extends TExpr
+	Field ident:String
+	Field value:Int
+
+	Method Create:TIdentExpr(ident:String, value:Int)
+		Self.ident = ident
+		Self.value = value
+		Return Self
+	End Method
+	
+	Method Eval:Int()
+		Return value
+	End Method
+	
+End Type
+
+Type TInt
+	Field value:Int
+	Method Create:TInt(value:Int)
+		Self.value = value
+		Return Self
+	End Method
+End Type
+
+Type TValues
+	Field values:TMap = New TMap
+	
+	Method Add(key:String, value:Int)
+		values.Insert(key, New TInt.Create(value))
+	End Method
+	
+	Method Value:Int(key:String)
+		Local obj:Object = values.ValueForKey(key)
+		If obj Then
+			Return TInt(obj).value
+		End If
+		Return 0
+	End Method
+	
+End Type
+
+Const TOK_IDENT:Int = 0
+Const TOK_NOT:Int = 1
+Const TOK_AND:Int = 2
+Const TOK_OR:Int = 3
+Const TOK_LPAREN:Int = 4
+Const TOK_RPAREN:Int = 5
+Const TOK_EOL:Int = 6
+