diff --git a/3d-viewer/3d_cache/3d_cache.cpp b/3d-viewer/3d_cache/3d_cache.cpp
index 5f99262eb7..18b6ad98de 100644
--- a/3d-viewer/3d_cache/3d_cache.cpp
+++ b/3d-viewer/3d_cache/3d_cache.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
- * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -29,7 +29,6 @@
 
 #include <wx/datetime.h>
 #include <wx/dir.h>
-#include <wx/filename.h>
 #include <wx/log.h>
 #include <wx/stdpaths.h>
 
@@ -55,6 +54,7 @@
 #include <project.h>
 #include <settings/common_settings.h>
 #include <settings/settings_manager.h>
+#include <wx_filename.h>
 
 
 #define MASK_3D_CACHE "3D_CACHE"
@@ -512,7 +512,7 @@ bool S3D_CACHE::Set3DConfigDir( const wxString& aConfigDir )
 
     wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), wxEmptyString );
 
-    cfgdir.Normalize();
+    cfgdir.Normalize( FN_NORMALIZE_FLAGS );
 
     if( !cfgdir.DirExists() )
     {
diff --git a/3d-viewer/3d_cache/3d_plugin_manager.cpp b/3d-viewer/3d_cache/3d_plugin_manager.cpp
index 705b1426d8..100d2dd2cc 100644
--- a/3d-viewer/3d_cache/3d_plugin_manager.cpp
+++ b/3d-viewer/3d_cache/3d_plugin_manager.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
- * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -29,13 +29,13 @@
 
 #include <wx/dir.h>
 #include <wx/dynlib.h>
-#include <wx/filename.h>
 #include <wx/log.h>
 #include <wx/stdpaths.h>
 #include <wx/string.h>
 
 #include <common.h>
 #include <paths.h>
+#include <wx_filename.h>
 #include "3d_plugin_manager.h"
 #include "plugins/3d/3d_plugin.h"
 #include "3d_cache/sg/scenegraph.h"
@@ -288,7 +288,7 @@ void S3D_PLUGIN_MANAGER::checkPluginName( const wxString& aPath,
 
     wxFileName path( ExpandEnvVarSubstitutions( aPath, nullptr ) );
 
-    path.Normalize();
+    path.Normalize( FN_NORMALIZE_FLAGS );
 
     // determine if the path is already in the list
     wxString wxpath = path.GetFullPath();
@@ -326,7 +326,7 @@ void S3D_PLUGIN_MANAGER::checkPluginPath( const wxString& aPath,
     else
         path.Assign( aPath, wxT( "" ) );
 
-    path.Normalize();
+    path.Normalize( FN_NORMALIZE_FLAGS );
 
     if( !wxFileName::DirExists( path.GetFullPath() ) )
         return;
diff --git a/3d-viewer/dialogs/dialog_select_3d_model.cpp b/3d-viewer/dialogs/dialog_select_3d_model.cpp
index 900181853a..c1a1452c40 100644
--- a/3d-viewer/dialogs/dialog_select_3d_model.cpp
+++ b/3d-viewer/dialogs/dialog_select_3d_model.cpp
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2016 Mario Luzeiro <mrluzeiro@ua.pt>
  * Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
- * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -34,6 +34,7 @@
 #include <common_ogl/ogl_attr_list.h>
 #include <filename_resolver.h>
 #include <pcbnew/footprint.h>
+#include <wx_filename.h>
 
 #include <wx/filedlg.h>
 
@@ -164,7 +165,7 @@ bool DIALOG_SELECT_3DMODEL::TransferDataFromWindow()
     // file selection mode: retrieve the filename and specify a
     // path relative to one of the config paths
     wxFileName fname = m_FileTree->GetFilePath();
-    fname.Normalize();
+    fname.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     m_model->m_Filename = m_resolver->ShortenPath( fname.GetFullPath() );
 
     return true;
diff --git a/common/filename_resolver.cpp b/common/filename_resolver.cpp
index c146fd9fbd..be74caebfc 100644
--- a/common/filename_resolver.cpp
+++ b/common/filename_resolver.cpp
@@ -26,7 +26,6 @@
 #include <mutex>
 #include <sstream>
 
-#include <wx/filename.h>
 #include <wx/log.h>
 #include <wx/msgdlg.h>
 #include <pgm_base.h>
@@ -34,6 +33,7 @@
 
 #include "common.h"
 #include "filename_resolver.h"
+#include <wx_filename.h>
 
 // configuration file version
 #define CFGFILE_VERSION 1
@@ -66,7 +66,7 @@ bool FILENAME_RESOLVER::Set3DConfigDir( const wxString& aConfigDir )
 
     wxFileName cfgdir( ExpandEnvVarSubstitutions( aConfigDir, m_project ), "" );
 
-    cfgdir.Normalize();
+    cfgdir.Normalize( FN_NORMALIZE_FLAGS );
 
     if( !cfgdir.DirExists() )
         return false;
@@ -87,7 +87,7 @@ bool FILENAME_RESOLVER::SetProject( PROJECT* aProject, bool* flgChanged )
 
     wxFileName projdir( ExpandEnvVarSubstitutions( aProject->GetProjectPath(), aProject ), "" );
 
-    projdir.Normalize();
+    projdir.Normalize( FN_NORMALIZE_FLAGS );
 
     if( !projdir.DirExists() )
         return false;
@@ -187,7 +187,7 @@ bool FILENAME_RESOLVER::createPathList()
             else
             {
                 fndummy.Assign( pathVal, "" );
-                fndummy.Normalize();
+                fndummy.Normalize( FN_NORMALIZE_FLAGS );
                 lpath.m_Pathexp = fndummy.GetFullPath();
             }
 
@@ -267,7 +267,7 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
     // working directory (which is not necessarily the current project directory)
     if( tmpFN.FileExists() )
     {
-        tmpFN.Normalize();
+        tmpFN.Normalize( FN_NORMALIZE_FLAGS );
         tname = tmpFN.GetFullPath();
 
         // special case: if a path begins with ${ENV_VAR} but is not in the resolver's path list
@@ -314,7 +314,7 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
         if( wxFileName::FileExists( fullPath ) )
         {
             tmpFN.Assign( fullPath );
-            tmpFN.Normalize();
+            tmpFN.Normalize( FN_NORMALIZE_FLAGS );
             tname = tmpFN.GetFullPath();
             return tname;
         }
@@ -331,7 +331,7 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
         fullPath = ExpandEnvVarSubstitutions( fullPath, m_project );
         fpath.Assign( fullPath );
 
-        if( fpath.Normalize() && fpath.FileExists() )
+        if( fpath.Normalize( FN_NORMALIZE_FLAGS ) && fpath.FileExists() )
         {
             tname = fpath.GetFullPath();
             return tname;
@@ -379,7 +379,7 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
 
                 wxFileName tmp( fullPath );
 
-                if( tmp.Normalize() )
+                if( tmp.Normalize( FN_NORMALIZE_FLAGS ) )
                     tname = tmp.GetFullPath();
 
                 return tname;
@@ -420,7 +420,7 @@ bool FILENAME_RESOLVER::addPath( const SEARCH_PATH& aPath )
 
     wxFileName path( ExpandEnvVarSubstitutions( tpath.m_Pathvar, m_project ), "" );
 
-    path.Normalize();
+    path.Normalize( FN_NORMALIZE_FLAGS );
 
     if( !path.DirExists() )
     {
@@ -494,7 +494,11 @@ bool FILENAME_RESOLVER::readPathList()
     }
 
     wxFileName cfgpath( m_configDir, RESOLVER_CONFIG );
-    cfgpath.Normalize();
+
+    // This should be the same as wxWidgets 3.0 wxPATH_NORM_ALL which is deprecated in 3.1.
+    // There are known issues with environment variable expansion so maybe we should be using
+    // our own ExpandEnvVarSubstitutions() here instead.
+    cfgpath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     wxString cfgname = cfgpath.GetFullPath();
 
     size_t nitems = m_paths.size();
@@ -714,7 +718,7 @@ void FILENAME_RESOLVER::checkEnvVarPath( const wxString& aPath )
     wxFileName tmpFN( ExpandEnvVarSubstitutions( lpath.m_Alias, m_project ), "" );
 
     wxUniChar psep = tmpFN.GetPathSeparator();
-    tmpFN.Normalize();
+    tmpFN.Normalize( FN_NORMALIZE_FLAGS );
 
     if( !tmpFN.DirExists() )
         return;
diff --git a/common/project.cpp b/common/project.cpp
index 6e49f79a5b..e79e29a8c5 100644
--- a/common/project.cpp
+++ b/common/project.cpp
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -267,7 +267,7 @@ const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const
     if( !fn.IsAbsolute() )
     {
         wxString pro_dir = wxPathOnly( GetProjectFullName() );
-        fn.Normalize( wxPATH_NORM_ALL, pro_dir );
+        fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, pro_dir );
     }
 
     return fn.GetFullPath();
diff --git a/eeschema/dialogs/dialog_plot_schematic.cpp b/eeschema/dialogs/dialog_plot_schematic.cpp
index a0589ed1e9..a84a73870f 100644
--- a/eeschema/dialogs/dialog_plot_schematic.cpp
+++ b/eeschema/dialogs/dialog_plot_schematic.cpp
@@ -4,7 +4,7 @@
  * Copyright (C) 1992-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
  * Copyright (C) 1992-2010 Lorenzo Marcantonio
  * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
- * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -38,6 +38,7 @@
 #include <trace_helpers.h>
 #include <settings/settings_manager.h>
 #include <drawing_sheet/ds_painter.h>
+#include <wx_filename.h>
 
 #include <sch_edit_frame.h>
 #include <sch_painter.h>
@@ -1294,7 +1295,7 @@ wxString DIALOG_PLOT_SCHEMATIC::getOutputPath()
             fn.SetName( wxEmptyString );
             fn.SetExt( wxEmptyString );
 
-            if( fn.Normalize() )
+            if( fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ) )
             {
                 path = fn.GetPath();
             }
@@ -1329,7 +1330,7 @@ wxString DIALOG_PLOT_SCHEMATIC::getOutputPath()
         // Build the absolute path of current output directory and the project path.
         fn.SetPath( Prj().GetProjectPath() + path );
 
-        if( fn.Normalize() )
+        if( fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ) )
         {
             path = fn.GetPath();
         }
diff --git a/eeschema/dialogs/dialog_sheet_properties.cpp b/eeschema/dialogs/dialog_sheet_properties.cpp
index 9a373abe5f..5f3a0bd3b9 100644
--- a/eeschema/dialogs/dialog_sheet_properties.cpp
+++ b/eeschema/dialogs/dialog_sheet_properties.cpp
@@ -29,6 +29,7 @@
 #include <wx/tooltip.h>
 #include <confirm.h>
 #include <validators.h>
+#include <wx_filename.h>
 #include <wildcards_and_files_ext.h>
 #include <widgets/tab_traversal.h>
 #include <kiplatform/ui.h>
@@ -445,7 +446,8 @@ bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilena
     // SCH_SCREEN file names are always absolute.
     wxFileName currentScreenFileName = currentScreen->GetFileName();
 
-    if( !screenFileName.Normalize( wxPATH_NORM_ALL, currentScreenFileName.GetPath() ) )
+    if( !screenFileName.Normalize(  FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
+                                    currentScreenFileName.GetPath() ) )
     {
         msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
                                    "'%s'\n"
diff --git a/eeschema/dialogs/dialog_symbol_remap.cpp b/eeschema/dialogs/dialog_symbol_remap.cpp
index fc22b944cd..5df4377429 100644
--- a/eeschema/dialogs/dialog_symbol_remap.cpp
+++ b/eeschema/dialogs/dialog_symbol_remap.cpp
@@ -6,7 +6,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2017 Wayne Stambaugh <stambaughw@gmail.com>
- * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software: you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -29,6 +29,7 @@
 #include <confirm.h>
 #include <reporter.h>
 #include <wildcards_and_files_ext.h>
+#include <wx_filename.h>
 #include <wx_html_report_panel.h>
 
 #include <symbol_library.h>
@@ -201,7 +202,7 @@ void DIALOG_SYMBOL_REMAP::createProjectSymbolLibTable( REPORTER& aReporter )
             wxFileName tmpFn = fullFileName;
 
             // Don't add symbol libraries that do not exist.
-            if( tmpFn.Normalize() && tmpFn.FileExists() )
+            if( tmpFn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ) && tmpFn.FileExists() )
             {
                 msg.Printf( _( "Adding library '%s', file '%s' to project symbol library table." ),
                             libName,
diff --git a/eeschema/sim/sim_plot_frame.cpp b/eeschema/sim/sim_plot_frame.cpp
index 317f1c955c..d629b55b7b 100644
--- a/eeschema/sim/sim_plot_frame.cpp
+++ b/eeschema/sim/sim_plot_frame.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2016 CERN
- * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  * @author Maciej Suminski <maciej.suminski@cern.ch>
  *
@@ -52,6 +52,7 @@
 #include <wx/ffile.h>
 #include <wx/filedlg.h>
 #include <dialog_shim.h>
+#include <wx_filename.h>
 
 
 SIM_PLOT_TYPE operator|( SIM_PLOT_TYPE aFirst, SIM_PLOT_TYPE aSecond )
@@ -1126,7 +1127,7 @@ wxString SIM_PLOT_FRAME::getDefaultPath()
 {
     wxFileName path = m_simulator->Settings()->GetWorkbookFilename();
 
-    path.Normalize( wxPATH_NORM_ALL, Prj().GetProjectPath() );
+    path.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, Prj().GetProjectPath() );
     return path.GetPath();
 }
 
diff --git a/eeschema/symbol_editor/symbol_library_manager.cpp b/eeschema/symbol_editor/symbol_library_manager.cpp
index 27b010f5b9..e2e3775535 100644
--- a/eeschema/symbol_editor/symbol_library_manager.cpp
+++ b/eeschema/symbol_editor/symbol_library_manager.cpp
@@ -31,6 +31,7 @@
 #include <pgm_base.h>
 #include <kiway.h>
 #include <profile.h>
+#include <wx_filename.h>
 #include <sch_io_mgr.h>
 #include <sch_plugins/legacy/sch_legacy_plugin.h>
 #include <symbol_lib_table.h>
@@ -210,10 +211,10 @@ bool SYMBOL_LIBRARY_MANAGER::SaveLibrary( const wxString& aLibrary, const wxStri
         if( row )
         {
             original = row->GetFullURI( true );
-            original.Normalize();
+            original.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
         }
 
-        destination.Normalize();
+        destination.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
 
         if( res && original == destination )
             libBuf.ClearDeletedBuffer();
diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp
index 16666de18b..465367d1fc 100644
--- a/eeschema/tools/sch_editor_control.cpp
+++ b/eeschema/tools/sch_editor_control.cpp
@@ -65,6 +65,7 @@
 #include <locale_io.h>
 
 #include <wildcards_and_files_ext.h>
+#include <wx_filename.h>
 #include <sch_sheet_path.h>
 #include <wx/filedlg.h>
 
@@ -1843,7 +1844,8 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
             if( !fn.IsAbsolute() )
             {
                 wxFileName currentSheetFileName = pasteRoot.LastScreen()->GetFileName();
-                fn.Normalize( wxPATH_NORM_ALL, currentSheetFileName.GetPath() );
+                fn.Normalize(  FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
+                               currentSheetFileName.GetPath() );
             }
 
             // Try to find the screen for the pasted sheet by several means
diff --git a/include/project.h b/include/project.h
index 5954aa38ff..7ddefa361e 100644
--- a/include/project.h
+++ b/include/project.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 2014-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -29,8 +29,8 @@
 #include <map>
 #include <vector>
 #include <kiid.h>
+#include <wx_filename.h>
 #include <wx/string.h>
-#include <wx/filename.h>
 #include <core/typeinfo.h>
 
 /// A variable name whose value holds the current project directory.
diff --git a/include/wx_filename.h b/include/wx_filename.h
index d8961f70e5..a66f60cd91 100644
--- a/include/wx_filename.h
+++ b/include/wx_filename.h
@@ -1,7 +1,7 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
+ * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -26,6 +26,18 @@
 
 #include <wx/filename.h>
 
+/**
+ * Default flags to pass to wxFileName::Normalize().
+ *
+ * @note wxPATH_NORM_ALL is deprecated in wxWidgets 3.1 and later.  wxPATH_NORM_ENV_VARS
+ *       is not included because it has some known issues and we typically use our own
+ *       ExpandEnvVarSubstitutions() for handling environment variable expansion.  If
+ *       ExpandEnvVarSubstitutions() is not used, logically or wxPATH_NORM_ENV_VARS to
+ *       this.
+ */
+#define FN_NORMALIZE_FLAGS ( wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE | \
+                             wxPATH_NORM_LONG | wxPATH_NORM_SHORTCUT )
+
 /**
  * A wrapper around a wxFileName which is much more performant with a subset of the API.
  *
diff --git a/kicad/dialogs/dialog_template_selector.cpp b/kicad/dialogs/dialog_template_selector.cpp
index 5669ea6dcd..d56cd81b55 100644
--- a/kicad/dialogs/dialog_template_selector.cpp
+++ b/kicad/dialogs/dialog_template_selector.cpp
@@ -24,6 +24,7 @@
 
 #include "dialog_template_selector.h"
 #include <bitmaps.h>
+#include <wx_filename.h>
 #include <wx/dir.h>
 #include <wx/dirdlg.h>
 #include <wx/settings.h>
@@ -182,7 +183,7 @@ void DIALOG_TEMPLATE_SELECTOR::AddTemplatesPage( const wxString& aTitle, wxFileN
 {
     wxNotebookPage* newPage = new wxNotebookPage( m_notebook, wxID_ANY );
 
-    aPath.Normalize();
+    aPath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     wxString path = aPath.GetFullPath();    // caller ensures this ends with file separator.
 
     TEMPLATE_SELECTION_PANEL* tpanel = new TEMPLATE_SELECTION_PANEL( newPage, path );
@@ -246,7 +247,7 @@ void DIALOG_TEMPLATE_SELECTOR::onDirectoryBrowseClicked( wxCommandEvent& event )
 {
     wxFileName fn;
     fn.AssignDir( m_tcTemplatePath->GetValue() );
-    fn.Normalize();
+    fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     wxString currPath = fn.GetFullPath();
 
     wxDirDialog dirDialog( this, _( "Select Templates Directory" ), currPath,
@@ -275,7 +276,7 @@ void DIALOG_TEMPLATE_SELECTOR::onReload( wxCommandEvent& event )
 
     wxFileName fn;
     fn.AssignDir( m_tcTemplatePath->GetValue() );
-    fn.Normalize();
+    fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     currPath = fn.GetFullPath();
     m_tcTemplatePath->SetValue( currPath );
 
diff --git a/kicad/pcm/pcm.cpp b/kicad/pcm/pcm.cpp
index cade83e0a6..e5365eda1b 100644
--- a/kicad/pcm/pcm.cpp
+++ b/kicad/pcm/pcm.cpp
@@ -30,6 +30,7 @@
 #include "pgm_base.h"
 #include "picosha2.h"
 #include "settings/settings_manager.h"
+#include <wx_filename.h>
 
 #include <fstream>
 #include <iomanip>
@@ -73,7 +74,7 @@ PLUGIN_CONTENT_MANAGER::PLUGIN_CONTENT_MANAGER( wxWindow* aParent ) : m_dialog(
 
     // Read and store pcm schema
     wxFileName schema_file( PATHS::GetStockDataPath( true ), "pcm.v1.schema.json" );
-    schema_file.Normalize();
+    schema_file.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     schema_file.AppendDir( "schemas" );
 
     std::ifstream  schema_stream( schema_file.GetFullPath().ToUTF8() );
diff --git a/plugins/3d/vrml/v2/vrml2_base.cpp b/plugins/3d/vrml/v2/vrml2_base.cpp
index 622e26e6b7..9bd7fd182b 100644
--- a/plugins/3d/vrml/v2/vrml2_base.cpp
+++ b/plugins/3d/vrml/v2/vrml2_base.cpp
@@ -26,9 +26,10 @@
 #include <sstream>
 #include <utility>
 #include <wx/string.h>
-#include <wx/filename.h>
 #include <wx/log.h>
 
+#include <wx_filename.h>
+
 #include "vrml2_base.h"
 #include "vrml2_transform.h"
 #include "vrml2_shape.h"
@@ -128,7 +129,7 @@ SGNODE* WRL2BASE::GetInlineData( const std::string& aName )
         fn.Assign( fname );
     }
 
-    if( !fn.Normalize() )
+    if( !fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS ) )
     {
         m_inlineModels.emplace( aName, nullptr );
         return nullptr;
diff --git a/plugins/3d/vrml/wrlproc.cpp b/plugins/3d/vrml/wrlproc.cpp
index 5a2ff0dbe3..9b06b61490 100644
--- a/plugins/3d/vrml/wrlproc.cpp
+++ b/plugins/3d/vrml/wrlproc.cpp
@@ -24,10 +24,10 @@
 
 #include <iostream>
 #include <sstream>
-#include <wx/filename.h>
 #include <wx/string.h>
 #include <wx/log.h>
 #include "wrlproc.h"
+#include <wx_filename.h>
 
 #define GETLINE                                                                                \
     do                                                                                         \
@@ -78,7 +78,7 @@ WRLPROC::WRLPROC( LINE_READER* aLineReader )
     wxFileName fn( tname );
 
     if( fn.IsRelative() )
-        fn.Normalize();
+        fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
 
     m_filedir = fn.GetPathWithSep().ToUTF8();
 
diff --git a/utils/idftools/idf2vrml.cpp b/utils/idftools/idf2vrml.cpp
index 678d8613b1..79f7d905d3 100644
--- a/utils/idftools/idf2vrml.cpp
+++ b/utils/idftools/idf2vrml.cpp
@@ -1,7 +1,8 @@
 /*
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
- * Copyright (C) 2014-2017  Cirilo Bernardo
+ * Copyright (C) 2014-2017 Cirilo Bernardo
+ * Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -35,7 +36,6 @@
 #include <wx/cmdline.h>
 #include <wx/log.h>
 #include <wx/string.h>
-#include <wx/filename.h>
 
 #include <iostream>
 #include <iomanip>
@@ -53,6 +53,8 @@
 #include <algorithm>
 #include <boost/ptr_container/ptr_map.hpp>
 
+#include <wx_filename.h>
+
 #include "idf_helpers.h"
 #include "idf_common.h"
 #include "idf_parser.h"
@@ -259,7 +261,7 @@ int IDF2VRML::OnRun()
     // Create the VRML file and write the header
     wxFileName fname( m_filename );
     fname.SetExt( wxT( "wrl" ) );
-    fname.Normalize();
+    fname.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     wxLogMessage( wxT( "Writing file: '%s'" ), fname.GetFullName() );
 
     OPEN_OSTREAM( ofile, fname.GetFullPath().ToUTF8() );
diff --git a/utils/kicad2step/pcb/3d_resolver.cpp b/utils/kicad2step/pcb/3d_resolver.cpp
index ea6241d026..c4971debbf 100644
--- a/utils/kicad2step/pcb/3d_resolver.cpp
+++ b/utils/kicad2step/pcb/3d_resolver.cpp
@@ -30,12 +30,13 @@
 #include <sstream>
 
 #include <wx/fileconf.h>
-#include <wx/filename.h>
 #include <wx/log.h>
 #include <wx/thread.h>
 #include <wx/msgdlg.h>
 #include <wx/stdpaths.h>
 
+#include <wx_filename.h>
+
 #include "3d_resolver.h"
 
 // configuration file version
@@ -138,7 +139,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName,
     {
         if( tmpFN.FileExists() )
         {
-            tmpFN.Normalize();
+            tmpFN.Normalize( FN_NORMALIZE_FLAGS );
             return tmpFN.GetFullPath();
         }
         else
@@ -149,7 +150,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName,
 
     // this case covers full paths, leading expanded vars, and paths relative to the current
     // working directory (which is not necessarily the current project directory)
-    tmpFN.Normalize();
+    tmpFN.Normalize( FN_NORMALIZE_FLAGS );
 
     if( tmpFN.FileExists() )
     {
@@ -194,7 +195,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName,
             fullPath = expandVars( fullPath );
 
         tmpFN.Assign( fullPath );
-        tmpFN.Normalize();
+        tmpFN.Normalize( FN_NORMALIZE_FLAGS );
 
         if( tmpFN.FileExists() )
         {
@@ -217,7 +218,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName,
         fullPath.Append( tname );
         fullPath = expandVars( fullPath );
         fpath.Assign( fullPath );
-        fpath.Normalize();
+        fpath.Normalize( FN_NORMALIZE_FLAGS );
 
         if( fpath.FileExists() )
         {
@@ -258,7 +259,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName,
                 fullPath = expandVars( fullPath );
 
             wxFileName tmp( fullPath );
-            tmp.Normalize();
+            tmp.Normalize( FN_NORMALIZE_FLAGS );
 
             if( tmp.FileExists() )
             {
@@ -296,7 +297,7 @@ bool S3D_RESOLVER::addPath( const SEARCH_PATH& aPath )
 #endif
 
     wxFileName path( tpath.m_Pathvar, wxT( "" ) );
-    path.Normalize();
+    path.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
 
     if( !path.DirExists() )
     {
@@ -363,7 +364,7 @@ bool S3D_RESOLVER::addPath( const SEARCH_PATH& aPath )
 bool S3D_RESOLVER::readPathList( void )
 {
     wxFileName cfgpath( wxStandardPaths::Get().GetTempDir(), S3D_RESOLVER_CONFIG );
-    cfgpath.Normalize();
+    cfgpath.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     wxString cfgname = cfgpath.GetFullPath();
 
     size_t nitems = m_Paths.size();
@@ -486,7 +487,7 @@ void S3D_RESOLVER::checkEnvVarPath( const wxString& aPath )
     lpath.m_Pathvar = lpath.m_Alias;
     wxFileName tmpFN( lpath.m_Alias, wxT( "" ) );
     wxUniChar psep = tmpFN.GetPathSeparator();
-    tmpFN.Normalize();
+    tmpFN.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
 
     if( !tmpFN.DirExists() )
         return;
diff --git a/utils/kicad2step/pcb/kicadpcb.cpp b/utils/kicad2step/pcb/kicadpcb.cpp
index 2e595e0730..4221233618 100644
--- a/utils/kicad2step/pcb/kicadpcb.cpp
+++ b/utils/kicad2step/pcb/kicadpcb.cpp
@@ -31,13 +31,12 @@
 #include <sexpr/sexpr.h>
 #include <sexpr/sexpr_parser.h>
 
-#include <wx/filename.h>
 #include <wx/wxcrtvararg.h>
 
 #include <memory>
 #include <string>
 
-
+#include <wx_filename.h>
 
 
 KICADPCB::KICADPCB( const wxString& aPcbName )
@@ -92,7 +91,7 @@ bool KICADPCB::ReadFile( const wxString& aFileName )
         return false;
     }
 
-    fname.Normalize();
+    fname.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
     m_filename = fname.GetFullPath();
 
     try