Howto:Disable Nasal entirely

From FlightGear wiki
Jump to: navigation, search
This article is a stub. You can help the wiki by expanding it.
Disable Nasal scripting
Started in 03/2014
Description provide an optional FlightGear startup mode to disable Nasal scripting entirely for regression testing purpososes
Contributor(s) Hooray
Status proof-of-concept (working patch)

Motivation

Nasal, and particularly its garbage collector (GC), is known for having a certain impact on the frame rate, and frame spacing - however, there are performance issues other than Nasal code, and some Nasal related issues (e.g. poorly-written code) may contribute to masking such issues - so far, it's been impossible to easily disable Nasal (the scripting subsystem in FlightGear) entirely - the following patch makes it possible to disable Nasal completely, so that it can be eliminated from the equation altogether. This startup mode will obviously only be of interest to developers and power-users, i.e. those interested in doing regression testing (imagine running fgfs in a gdb/valgrind or Built-in Profiler session or even just viewing the OSG on screen stats without any scripting overhead), and understanding FlightGear issues (resource leaks, performance issues etc).

Cquote1.png Instead of adding just-another-feature we need to strip it down to getting a fast and constand fps rendering engine. Everything else needs to run outside the main loop and has to interact with the core by, say HLA/RTI or whatever IPC we have.
Cquote2.png
Cquote1.png I'd just recommend [...] to focus on detangling the subsystems and creating a distributes simulation instead. That's my vision.
Cquote2.png
Cquote1.png In general, FG has quite a few data dependencies internally which make multi-threading challenging right now - there's groundwork to make the data-dependencies more explicit (i.e, via the property tree) that has to happen before pieces can easily move to other threads.
— James Turner (Oct 3rd, 2008). Re: [Flightgear-devel] multi-threading / CPU usage.
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png What would simplify this greatly is if subsystem registration was totally separated out from (re-)initialisation, and if sub-systems had run-level or priority associated with them. All the subsystems could be registered via add_subsystem, and then during fgInitSubsystems, the runlevel would gradually advance to the final value. This also means the dependencies between subsystems can be expressed (higher numbers depend on lower numbers), and might make things like reset more simple (lower the run-level back to some determined value, and the bring it back up again).
— James Turner (Apr 17th, 2006). [Flightgear-devel] Subsystem run-levels.
(powered by Instant-Cquotes)
Cquote2.png

Objective

provide a startup option (boolean property) to disable the Nasal scripting engine in FlightGear to help with regression testing.

before Nasal can go, or even just alternatives be considered, people need to understand why FGPythonSys would suffer from the same restrictions.

HLA is all great and dandy, but for that to actually work and be beneficial, certain groundwork has to happen first - and that involves making Nasal entirely optional, so that we can get rid of the hard-coded assumption that Nasal is always up and running. The next step is making subsystem initialiation incremental in its entirety - which also entails stopping to load all sorts of subsystem-specific Nasal scripts despite some subsystems having become optional these days (thanks to James reset/re-init work). In other words, imagine a scenario where ATC-chatter is loaded but sound is not running/disabled, or the tanker scenario/script with AI disabled (and even moreso Bombable), or gui.nas loaded without PUI being active etc. And like many people have stated previously, the extreme use of Nasal embedded in GUI dialogs has to stop, too - it's hugely chaotic and almost perverse, it is adding tons of problems, and making it next to impossile to come up with other UIs. Equally, even the way people code avionics is problematic from the standpoint of wanting a simulation without Nasal in the main loop - as it doesn't scale, it also assumes that Nasal is always running in the main loop - so once/if people shuffle it out of the main loop, there would be all sorts of race conditions (=crashes) caused by such code. The way Nasal is used in FlightGear is certainly very problematic, but before FGPythonSys (or other alternatives) can be considered, there are a handful of things that need to happen first, e.g.:

  • providing an option to disable Nasal entirely: Howto:Disable Nasal entirely
  • allow Nasal to be stopped/restarted and removed/re-added at runtime using the subsystemFactory/fgcommands
  • providing an option to initialize Nasal much earlier and better formalize subsystem/script dependencies: Initializing Nasal early
  • get rid of Nasal hacks commonly used in GUI dialogs and MFDs, i.e. introduce dedicated XML tags for common hacks (think widgets) and instead of having blobs of Nasal code, introduce fgcommands (possibly just mapped to Nasal code), so that other GUIs (think Phi/qt5) can support those files without them having to support Nasal
  • Integrating IPC/RPC functionality, so that Nasal interpreters can access other subsystem specific property trees without causing race conditions
  • Allow multiple instances of the scripting interpreter to be instantiated, so that these can run in different threads - e.g. with aircraft/scenery scripts running separately from GUI or weather/environmental scripts.

[1]

Background

  • Nasal performance
  • garbage collection overhead
  • impact on frame rate and frame spacing
Cquote1.png I should still have an old topic branch that disabled FGNasalSys entirely - i.e. the fg_init.cxx, but also the roughly ~10 places where a handle (pointer) to the FGNasalSys instance in the SGSubsysmMgr is acquired to run some Nasal code on demand (think GUI, joystick, keyboard, AI/scenery stuff).

In and of itself, that will obviously not be particularly useful, because fgfs is rather "crippled" with so much of its (current) UI/aircraft functionality tied to Nasal code all over the place, but it may still be interesting for the FGPythonSys effort, because it provides a good baseline for fgfs performance without _any_ Nasal code running at all, including obviously GC issues - even if only to illustrate (and prove) that FlightGear is still suffering from resource leaks and race conditions that have nothing to do with Nasal.

In other words, this is something where FGPythonSys and FGNasalSys could benefit eachother in the near term, while providing benefits for FG in the long term.
Cquote2.png
Cquote1.png that could be quite useful for experimentation purposes, unit testing, and maybe coming up with a FGScriptingSys base class.
Cquote2.png

Status

Cquote1.png in its current form it cannot be committed "as is", because it does not deal with scenery/tile related Nasal hooks, i.e. those using NasalModelData* - which is primarily the scenery/tile manager code, AIBase and the CanvasMgr stuff.

Those are the locations that would need to also use a FGNasalSys NULL pointer check and skip the execution of the corresponding portions of the code. I never ran into this because I used the minimal startup profile (as per the wiki) to do the corresponding troubleshooting, with AI and scenery/terrain stuff also disabled entirely.

Like I said, it wasn't really intended to be used "as is" - you definitely need to know what you're doing. Apart from that, someone using this "mode" would obviously also understand where a FGNasalSys related segfaults come from with Nasal disabled
Cquote2.png

News / Updates

Changelog

Gallery

Roadmap

Template:Roadmap

Related

fgfs.log

view:3:$FG_SRC/Viewer/splash.cxx:445:Splash screen progress finishing-subsystems
nasal:5:$FG_SRC/Main/fg_init.cxx:912:Nasal support disabled:Initialization
general:3:$FG_SRC/Time/TimeManager.cxx:411:After TimeManager::setTimeOffset(): warp = 0
nasal:5:$FG_SRC/Network/HTTPClient.cxx:331:Nasal support disabled:package manager
instruments:3:$FG_SRC/Instrumentation/gps.cxx:377:GPS saw route-manager flight-plan replaced.
autopilot:3:$FG_SRC/Autopilot/route_mgr.cxx:780:route manager, current-wp is now -1
nasal:5:$FG_SRC/Input/FGKeyboardInput.cxx:118:Nasal support disabled:Keyboard bindings
ai:3:$FG_SRC/AIModel/AIManager.cxx:167:loading scenario 'nimitz_demo'
general:3:$FG_SRC/Main/fg_init.cxx:916:Subsystems postinit took:48
general:3:$FG_SRC/Main/fg_init.cxx:925:

Patch

This article or section contains out-of-date information

Please help improve this article by updating it. There may be additional information on the talk page.

Note  The following patch only works during startup/initialization, i.e. set the boolean property

/sim/startup/disable-nasal via something like --prop:/sim/startup/disable-nasal=1 and the initialization of the Nasal susbystem (FGNasalSys) will be disabled, as well as all calls (?) to the system from other subsystems (GUI, Canvas, bindings, package manager etc). If you should be seeing FGNasalSys related segfaults with this patch committed/active, that would suggest that not all Nasal access has been disabled yet (straightforward to fix)


diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx
index 4faf23e..aaca4b9 100644
--- a/src/AIModel/AIManager.cxx
+++ b/src/AIModel/AIManager.cxx
@@ -71,7 +71,11 @@ public:
         _unloadScript = nasalScripts->getStringValue("unload");
         std::string loadScript = nasalScripts->getStringValue("load");
         if (!loadScript.empty()) {
-            FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+            FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
+	    if(!nasalSys) { // TODO: check this during reset when AI scenarios are still booting
+		NASAL_DISABLED("load AI scenario");
+		return;
+	    }
             std::string moduleName = "scenario_" + _internalName;
             nasalSys->createModule(moduleName.c_str(), moduleName.c_str(),
                                    loadScript.c_str(), loadScript.size(),
@@ -85,9 +89,11 @@ public:
             ai->setDie(true);
         }
         
-        FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
-        if (!nasalSys)
-            return;
+        FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
+        if(!nasalSys) { 
+		NASAL_DISABLED("unload AI scenarios");
+		return;
+	    }
         
         std::string moduleName = "scenario_" + _internalName;
         if (!_unloadScript.empty()) {
diff --git a/src/GUI/CanvasWidget.cxx b/src/GUI/CanvasWidget.cxx
index f68fe22..c8dcc6a 100644
--- a/src/GUI/CanvasWidget.cxx
+++ b/src/GUI/CanvasWidget.cxx
@@ -71,11 +71,14 @@ CanvasWidget::CanvasWidget( int x, int y,
   if( !nasal )
     return;
 
-  FGNasalSys *nas = dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
-  if( !nas )
+  FGNasalSys *nas = globals->get_subsystem<FGNasalSys>();
+  if( !nas ) {
     SG_LOG( SG_GENERAL,
             SG_ALERT,
             "CanvasWidget: Failed to get nasal subsystem!" );
+  NASAL_DISABLED("PUI CanvasWidget");
+  return;
+  }
 
   const std::string file = std::string("__canvas:")
                          + cprops->getStringValue("name");
diff --git a/src/GUI/FGPUIDialog.cxx b/src/GUI/FGPUIDialog.cxx
index 30cbef7..e9a0848 100644
--- a/src/GUI/FGPUIDialog.cxx
+++ b/src/GUI/FGPUIDialog.cxx
@@ -669,10 +669,12 @@ FGPUIDialog::FGPUIDialog (SGPropertyNode *props) :
         SGPropertyNode *open = nasal->getNode("open");
         if (open) {
             const char *s = open->getStringValue();
-            FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
+            FGNasalSys *nas = globals->get_subsystem<FGNasalSys>();
             if (nas)
                 nas->createModule(_module.c_str(), _module.c_str(), s, strlen(s), props);
+	    else NASAL_DISABLED("Nasal embedded in PUI dialogs");	
         }
+		
     }
     display(props);
 }
@@ -684,7 +686,7 @@ FGPUIDialog::~FGPUIDialog ()
     _props->setIntValue("lastx", x);
     _props->setIntValue("lasty", y);
 
-    FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
+    FGNasalSys *nas = globals->get_subsystem<FGNasalSys>();
     if (nas) {
         if (_nasal_close) {
             const char *s = _nasal_close->getStringValue();
@@ -1055,8 +1057,12 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
             obj->setBuffer(tsync->log());
           }
         } else {
-          FGNasalSys* nasal = (FGNasalSys*) globals->get_subsystem("nasal");
+          FGNasalSys* nasal = globals->get_subsystem<FGNasalSys>();
+	  if(nasal) 	  
           obj->setBuffer(nasal->log());
+	  else {
+	  NASAL_DISABLED("PUI");
+	  }
         }
 
         setupObject(obj, props);
diff --git a/src/GUI/FileDialog.cxx b/src/GUI/FileDialog.cxx
index 2047898..1c091f8 100644
--- a/src/GUI/FileDialog.cxx
+++ b/src/GUI/FileDialog.cxx
@@ -99,15 +99,22 @@ public:
         func(f),
         object(obj)
     {
-        FGNasalSys* sys = static_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+        FGNasalSys* sys = globals->get_subsystem<FGNasalSys>();
+        if(!sys) {
+	NASAL_DISABLED("FileDialog");
+	 return;
+	}
         _gcKeys[0] = sys->gcSave(f);
         _gcKeys[1] = sys->gcSave(obj);
     }
     
     virtual void onFileDialogDone(FGFileDialog* instance, const SGPath& aPath)
     {
-        FGNasalSys* sys = static_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
-        
+        FGNasalSys* sys = globals->get_subsystem<FGNasalSys>();
+        if(!sys) {
+	NASAL_DISABLED("FileDialog (done)");
+	return;
+	} 
         naContext ctx = naNewContext();
         naRef args[1];
         args[0] = nasal::to_nasal(ctx, aPath);
@@ -118,7 +125,11 @@ public:
     
     ~NasalCallback()
     {
-        FGNasalSys* sys = static_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+        FGNasalSys* sys = globals->get_subsystem<FGNasalSys>();
+	if(!sys) {
+	NASAL_DISABLED("FileDialog");
+	return;
+	}
         sys->gcRelease(_gcKeys[0]);
         sys->gcRelease(_gcKeys[1]);
     }
diff --git a/src/Input/FGEventInput.cxx b/src/Input/FGEventInput.cxx
index 29bdc6e..2cd0844 100644
--- a/src/Input/FGEventInput.cxx
+++ b/src/Input/FGEventInput.cxx
@@ -224,7 +224,7 @@ void FGButtonEvent::fire( FGEventData & eventData )
 
 FGInputDevice::~FGInputDevice()
 {
-  FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
+  FGNasalSys *nas = globals->get_subsystem<FGNasalSys>();
   if (nas && deviceNode ) {
     SGPropertyNode_ptr nasal = deviceNode->getNode("nasal");
     if( nasal ) {
@@ -236,6 +236,7 @@ FGInputDevice::~FGInputDevice()
     }
     nas->deleteModule(nasalModule.c_str());
   }
+  else NASAL_DISABLED("FGInputDevice");
 } 
 
 void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
@@ -261,10 +262,10 @@ void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
     SGPropertyNode_ptr open = nasal->getNode("open");
     if (open) {
       const string s = open->getStringValue();
-      FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
+      FGNasalSys *nas = globals->get_subsystem<FGNasalSys>();
       if (nas)
         nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s.c_str(), s.length(), deviceNode );
-    }
+    } else NASAL_DISABLED("FGInputDevice::Configure");
   }
 
 }
diff --git a/src/Input/FGJoystickInput.cxx b/src/Input/FGJoystickInput.cxx
index 069e9d8..046b8ce 100644
--- a/src/Input/FGJoystickInput.cxx
+++ b/src/Input/FGJoystickInput.cxx
@@ -163,7 +163,7 @@ void FGJoystickInput::reinit() {
 
 void FGJoystickInput::postinit()
 {
-  FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
+  FGNasalSys *nasalsys = globals->get_subsystem<FGNasalSys>();
   SGPropertyNode_ptr js_nodes = fgGetNode("/input/joysticks");
 
   for (int i = 0; i < MAX_JOYSTICKS; i++) {
@@ -208,14 +208,16 @@ void FGJoystickInput::postinit()
     std::ostringstream str;
     str << "__js" << i;
     std::string module = str.str();
+    unsigned int j;
+    if (nasalsys) {
     nasalsys->createModule(module.c_str(), module.c_str(), "", 0);
 
     PropertyList nasal = js_node->getChildren("nasal");
-    unsigned int j;
     for (j = 0; j < nasal.size(); j++) {
       nasal[j]->setStringValue("module", module.c_str());
       nasalsys->handleCommand(nasal[j]);
     }
+    } else NASAL_DISABLED("Joystick bindings");
 
     //
     // Initialize the axes.
diff --git a/src/Input/FGKeyboardInput.cxx b/src/Input/FGKeyboardInput.cxx
index 8ff3d0a..716bdcb 100644
--- a/src/Input/FGKeyboardInput.cxx
+++ b/src/Input/FGKeyboardInput.cxx
@@ -108,12 +108,14 @@ void FGKeyboardInput::postinit()
     key_nodes = fgGetNode("/input/keyboard", true);
   }
 
-  FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
+  FGNasalSys *nasalsys = globals->get_subsystem<FGNasalSys>();
+  if(nasalsys) {
   PropertyList nasal = key_nodes->getChildren("nasal");
   for (unsigned int j = 0; j < nasal.size(); j++) {
     nasal[j]->setStringValue("module", module.c_str());
     nasalsys->handleCommand(nasal[j]);
   }
+} else NASAL_DISABLED("Keyboard bindings");
 
   PropertyList keys = key_nodes->getChildren("key");
   for (unsigned int i = 0; i < keys.size(); i++) {
diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx
index 1e93a0b..26ed72c 100644
--- a/src/Main/fg_commands.cxx
+++ b/src/Main/fg_commands.cxx
@@ -185,7 +185,13 @@ do_null (const SGPropertyNode * arg)
 static bool
 do_nasal (const SGPropertyNode * arg)
 {
-    return ((FGNasalSys*)globals->get_subsystem("nasal"))->handleCommand(arg);
+    FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
+    if(!nasalSys) {
+	NASAL_DISABLED("fgcomand nasal (bindings)");
+	return false;
+    }
+    return nasalSys->handleCommand(arg);
+    
 }
 
 /**
diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx
index 61d3425..1290087 100644
--- a/src/Main/fg_init.cxx
+++ b/src/Main/fg_init.cxx
@@ -469,7 +469,7 @@ int fgInitConfig ( int argc, char **argv, bool reinit )
       SG_LOG(SG_INPUT, SG_INFO, "Reading global preferences");
       fgLoadProps("preferences.xml", globals->get_props());
       SG_LOG(SG_INPUT, SG_INFO, "Finished Reading global preferences");
-        
+    
       // do not load user settings when reset to default is requested, or if
       // told to explicitly ignore
       if (options->isOptionSet("restore-defaults") || options->isOptionSet("ignore-autosave"))
@@ -904,11 +904,19 @@ void fgPostInitSubsystems()
     // Initialize the Nasal interpreter.
     // Do this last, so that the loaded scripts see initialized state
     ////////////////////////////////////////////////////////////////////////
+if(!fgGetBool("/sim/startup/disable-nasal",false)) {
     FGNasalSys* nasal = new FGNasalSys();
     globals->add_subsystem("nasal", nasal, SGSubsystemMgr::INIT);
     nasal->init();
     SG_LOG(SG_GENERAL, SG_INFO, "Nasal init took:" << st.elapsedMSec());
-
+}   else { 
+	NASAL_DISABLED("Initialization");
+	SG_LOG(SG_GENERAL, SG_ALERT, 
+	"Warning: Nasal being disabled will render most of the current UI (PUI/Canvas) and "
+	"aircraft/scenery scripts non-functional. This startup mode is only intended for "
+	" developers and power users wanting to do regression testing! "
+	"You are advised to use Phi and/or the telnet/props protocol to control FG in this  mode");
+    }
     // initialize methods that depend on other subsystems.
     st.stamp();
     globals->get_subsystem_mgr()->postinit();
@@ -1004,10 +1012,12 @@ void fgStartNewReset()
     SGSubsystemMgr* subsystemManger = globals->get_subsystem_mgr();
     // Nasal is manually inited in fgPostInit, ensure it's already shutdown
     // before other subsystems, so Nasal listeners don't fire during shutdown
-    SGSubsystem* nasal = subsystemManger->get_subsystem("nasal");
+    SGSubsystem* nasal = subsystemManger->get_subsystem<FGNasalSys>();
+    if(nasal) {
     nasal->shutdown();
     nasal->unbind();
     subsystemManger->remove("nasal");
+    } else NASAL_DISABLED("reset");
     
     subsystemManger->shutdown();
     subsystemManger->unbind();
diff --git a/src/Main/options.cxx b/src/Main/options.cxx
index 3c412ca..2292e3e 100644
--- a/src/Main/options.cxx
+++ b/src/Main/options.cxx
@@ -1706,6 +1706,7 @@ struct OptionDesc {
     {"no-default-config",            false, OPTION_IGNORE, "", false, "", 0},
     {"prop",                         true,  OPTION_FUNC | OPTION_MULTI,   "", false, "", fgOptSetProperty},
     {"load-tape",                    true,  OPTION_FUNC,   "", false, "", fgOptLoadTape },
+    {"disable-nasal",		     false, OPTION_BOOL,  "/sim/startup/disable-nasal", true, "", 0 },
     {0}
 };
 
diff --git a/src/Network/ATC-Main.cxx b/src/Network/ATC-Main.cxx
index 6c0da9b..68e0436 100644
--- a/src/Network/ATC-Main.cxx
+++ b/src/Network/ATC-Main.cxx
@@ -222,11 +222,13 @@ bool FGATCMain::process() {
     // functionality from the interface than the ATC hardware can
     // directly provide.
 
-    FGNasalSys *n = (FGNasalSys*)globals->get_subsystem("nasal");
+    FGNasalSys *n = globals->get_subsystem<FGNasalSys>();
+    if(n) {
     bool result = n->parseAndRun( "atcsim.update()" );
     if ( !result ) {
         SG_LOG( SG_NETWORK, SG_ALERT, "Nasal: atcsim.update() failed!" );
     }
+    } else NASAL_DISABLED("ATC-Main");
 
     // process the ATC outputs
     if ( output0 != NULL && board0_locked ) {
diff --git a/src/Network/HTTPClient.cxx b/src/Network/HTTPClient.cxx
index e6d2b29..fc20c20 100644
--- a/src/Network/HTTPClient.cxx
+++ b/src/Network/HTTPClient.cxx
@@ -326,7 +326,11 @@ void FGHTTPClient::postinit()
   
   pkg::Root* packageRoot = globals->packageRoot();
   if (packageRoot) {
-    FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+    FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
+    if(!nasalSys) {
+	NASAL_DISABLED("package manager");
+	return;
+	}
     nasal::Hash nasalGlobals = nasalSys->getGlobals();
     nasal::Hash nasalPkg = nasalGlobals.createHash("pkg"); // module
     nasalPkg.set("root", packageRoot);
diff --git a/src/Scripting/NasalModelData.cxx b/src/Scripting/NasalModelData.cxx
index e4f2269..f59c6a5 100644
--- a/src/Scripting/NasalModelData.cxx
+++ b/src/Scripting/NasalModelData.cxx
@@ -116,7 +116,12 @@ void FGNasalModelData::load()
   SG_LOG(SG_NASAL, SG_DEBUG, "Loading nasal module " << _module.c_str());
 
   const char *s = _load ? _load->getStringValue() : "";
-  FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+  FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
+
+  if(!nasalSys) {
+	NASAL_DISABLED("NasalModelData");
+	return;
+  }
 
   // Add _module_id to script local hash to allow placing canvasses on objects
   // inside the model.
@@ -140,7 +145,7 @@ void FGNasalModelData::unload()
     if (_module.empty())
         return;
 
-    FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+    FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
     if(!nasalSys) {
         SG_LOG(SG_NASAL, SG_WARN, "Trying to run an <unload> script "
                "without Nasal subsystem present.");
@@ -183,7 +188,7 @@ FGNasalModelData* FGNasalModelData::getByModuleId(unsigned int id)
 //------------------------------------------------------------------------------
 FGNasalModelDataProxy::~FGNasalModelDataProxy()
 {
-    FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+    FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
     // when necessary, register Nasal module to be destroyed/unloaded
     // in the main thread.
     if ((_data.valid())&&(nasalSys))
@@ -205,7 +210,7 @@ void FGNasalModelDataProxy::modelLoaded( const std::string& path,
     if(!nasal)
         return;
     
-    FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+    FGNasalSys* nasalSys = globals->get_subsystem<FGNasalSys>();
     if(!nasalSys)
     {
         SG_LOG
diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx
index 55c79a2..a427c64 100644
--- a/src/Scripting/NasalPositioned.cxx
+++ b/src/Scripting/NasalPositioned.cxx
@@ -1830,7 +1830,11 @@ class NasalFPDelegateFactory : public FlightPlan::DelegateFactory
 public:
   NasalFPDelegateFactory(naRef code)
   {
-    _nasal = (FGNasalSys*) globals->get_subsystem("nasal");
+    _nasal = globals->get_subsystem<FGNasalSys>();
+    if(!_nasal) {
+	NASAL_DISABLED("Nasal flightplan delegates");
+	return;
+	}
     _func = code;
     _gcSaveKey = _nasal->gcSave(_func);
   }
diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx
index 096a591..d0124be 100644
--- a/src/Scripting/NasalSys.hxx
+++ b/src/Scripting/NasalSys.hxx
@@ -30,11 +30,15 @@ namespace simgear { class BufferedLogCallback; }
 
 SGPropertyNode* ghostToPropNode(naRef ref);
 
+#define NASAL_DISABLED(feature) SG_LOG(SG_NASAL, SG_ALERT, "Nasal support disabled:" << feature)
+
 class FGNasalSys : public SGSubsystem
 {
 public:
     FGNasalSys();
     virtual ~FGNasalSys();
+    static const char* subsystemName() { return "nasal"; }
+
     virtual void init();
     virtual void shutdown();
  1. Hooray  (Oct 29th, 2016).  Re: Nasal must go .