New kicad-cli will now be the cli interface
This commit is contained in:
parent
85623656a6
commit
3fe004fd1b
|
@ -287,9 +287,9 @@ set( COMMON_SRCS
|
||||||
${PLUGINS_CADSTAR_SRCS}
|
${PLUGINS_CADSTAR_SRCS}
|
||||||
${PLUGINS_EAGLE_SRCS}
|
${PLUGINS_EAGLE_SRCS}
|
||||||
${FONT_SRCS}
|
${FONT_SRCS}
|
||||||
cli/command_export_kicad_pcbnew.cpp
|
|
||||||
cli/command_export_pcb_svg.cpp
|
cli/command_export_pcb_svg.cpp
|
||||||
cli/command_export_pcbnew.cpp
|
cli/command_pcb.cpp
|
||||||
|
cli/command_pcb_export.cpp
|
||||||
cli/command_export_step.cpp
|
cli/command_export_step.cpp
|
||||||
jobs/job_export_step.cpp
|
jobs/job_export_step.cpp
|
||||||
jobs/job_dispatcher.cpp
|
jobs/job_dispatcher.cpp
|
||||||
|
|
|
@ -18,13 +18,15 @@
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "command_export_pcbnew.h"
|
#include "command_pcb.h"
|
||||||
|
|
||||||
CLI::EXPORT_PCBNEW_COMMAND::EXPORT_PCBNEW_COMMAND() : COMMAND( "export" )
|
CLI::PCB_COMMAND::PCB_COMMAND() : COMMAND( "pcb" )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int CLI::EXPORT_PCBNEW_COMMAND::Perform( KIWAY& aKiway ) const
|
int CLI::PCB_COMMAND::Perform( KIWAY& aKiway ) const
|
||||||
{
|
{
|
||||||
return 0;
|
std::cout << m_argParser;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
|
@ -25,9 +25,9 @@
|
||||||
|
|
||||||
namespace CLI
|
namespace CLI
|
||||||
{
|
{
|
||||||
struct EXPORT_PCBNEW_COMMAND : public COMMAND
|
struct PCB_COMMAND : public COMMAND
|
||||||
{
|
{
|
||||||
EXPORT_PCBNEW_COMMAND();
|
PCB_COMMAND();
|
||||||
|
|
||||||
int Perform( KIWAY& aKiway ) const override;
|
int Perform( KIWAY& aKiway ) const override;
|
||||||
};
|
};
|
|
@ -18,14 +18,16 @@
|
||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "command_export_kicad_pcbnew.h"
|
#include "command_pcb_export.h"
|
||||||
|
|
||||||
CLI::EXPORT_KICAD_PCBNEW_COMMAND::EXPORT_KICAD_PCBNEW_COMMAND() : COMMAND( "export-pcb" )
|
CLI::EXPORT_PCB_COMMAND::EXPORT_PCB_COMMAND() : COMMAND( "export" )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CLI::EXPORT_KICAD_PCBNEW_COMMAND::Perform( KIWAY& aKiway ) const
|
int CLI::EXPORT_PCB_COMMAND::Perform( KIWAY& aKiway ) const
|
||||||
{
|
{
|
||||||
return 0;
|
std::cout << m_argParser;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
|
@ -25,9 +25,9 @@
|
||||||
|
|
||||||
namespace CLI
|
namespace CLI
|
||||||
{
|
{
|
||||||
struct EXPORT_KICAD_PCBNEW_COMMAND : public COMMAND
|
struct EXPORT_PCB_COMMAND : public COMMAND
|
||||||
{
|
{
|
||||||
EXPORT_KICAD_PCBNEW_COMMAND();
|
EXPORT_PCB_COMMAND();
|
||||||
|
|
||||||
int Perform( KIWAY& aKiway ) const override;
|
int Perform( KIWAY& aKiway ) const override;
|
||||||
};
|
};
|
|
@ -506,8 +506,11 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit )
|
||||||
|
|
||||||
// This sets the maximum tooltip display duration to 10s (up from 5) but only affects
|
// This sets the maximum tooltip display duration to 10s (up from 5) but only affects
|
||||||
// Windows as other platforms display tooltips while the mouse is not moving
|
// Windows as other platforms display tooltips while the mouse is not moving
|
||||||
wxToolTip::Enable( true );
|
if( !aHeadless )
|
||||||
wxToolTip::SetAutoPop( 10000 );
|
{
|
||||||
|
wxToolTip::Enable( true );
|
||||||
|
wxToolTip::SetAutoPop( 10000 );
|
||||||
|
}
|
||||||
|
|
||||||
if( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval != 0 )
|
if( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval != 0 )
|
||||||
wxUpdateUIEvent::SetUpdateInterval( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval );
|
wxUpdateUIEvent::SetUpdateInterval( ADVANCED_CFG::GetCfg().m_UpdateUIEventInterval );
|
||||||
|
|
|
@ -483,7 +483,7 @@ bool SETTINGS_MANAGER::MigrateIfNeeded()
|
||||||
if( m_headless )
|
if( m_headless )
|
||||||
{
|
{
|
||||||
wxLogTrace( traceSettings, wxT( "Settings migration not checked; running headless" ) );
|
wxLogTrace( traceSettings, wxT( "Settings migration not checked; running headless" ) );
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxFileName path( GetUserSettingsPath(), "" );
|
wxFileName path( GetUserSettingsPath(), "" );
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include <wx/stdpaths.h>
|
#include <wx/stdpaths.h>
|
||||||
#include <wx/snglinst.h>
|
#include <wx/snglinst.h>
|
||||||
#include <wx/html/htmlwin.h>
|
#include <wx/html/htmlwin.h>
|
||||||
#include <argparse/argparse.hpp>
|
|
||||||
|
|
||||||
#include <kiway.h>
|
#include <kiway.h>
|
||||||
#include <pgm_base.h>
|
#include <pgm_base.h>
|
||||||
|
@ -49,14 +48,9 @@
|
||||||
#include <confirm.h>
|
#include <confirm.h>
|
||||||
#include <settings/settings_manager.h>
|
#include <settings/settings_manager.h>
|
||||||
|
|
||||||
#include <kicad_build_version.h>
|
|
||||||
#include <kiplatform/app.h>
|
#include <kiplatform/app.h>
|
||||||
#include <kiplatform/environment.h>
|
#include <kiplatform/environment.h>
|
||||||
|
|
||||||
#include "cli/command_export_pcbnew.h"
|
|
||||||
#include "cli/command_export_pcb_svg.h"
|
|
||||||
#include "cli/command_export_step.h"
|
|
||||||
#include "cli/exit_codes.h"
|
|
||||||
|
|
||||||
// Only a single KIWAY is supported in this single_top top level component,
|
// Only a single KIWAY is supported in this single_top top level component,
|
||||||
// which is dedicated to loading only a single DSO.
|
// which is dedicated to loading only a single DSO.
|
||||||
|
@ -280,36 +274,8 @@ struct APP_SINGLE_TOP : public wxApp
|
||||||
IMPLEMENT_APP( APP_SINGLE_TOP )
|
IMPLEMENT_APP( APP_SINGLE_TOP )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct COMMAND_ENTRY
|
|
||||||
{
|
|
||||||
CLI::COMMAND* handler;
|
|
||||||
|
|
||||||
std::vector<COMMAND_ENTRY> subCommands;
|
|
||||||
|
|
||||||
COMMAND_ENTRY( CLI::COMMAND* aHandler ) : handler( aHandler ){};
|
|
||||||
COMMAND_ENTRY( CLI::COMMAND* aHandler, std::vector<COMMAND_ENTRY> aSub ) :
|
|
||||||
handler( aHandler ), subCommands( aSub ) {};
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef PCBNEW
|
|
||||||
static CLI::EXPORT_STEP_COMMAND stepCmd{};
|
|
||||||
static CLI::EXPORT_PCB_SVG_COMMAND svgCmd{};
|
|
||||||
static CLI::EXPORT_PCBNEW_COMMAND exportCmd{};
|
|
||||||
|
|
||||||
static std::vector<COMMAND_ENTRY> commandStack = {
|
|
||||||
{ &exportCmd, { &stepCmd, &svgCmd } }
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
|
|
||||||
static std::vector<COMMAND_ENTRY> commandStack = {
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool PGM_SINGLE_TOP::OnPgmInit()
|
bool PGM_SINGLE_TOP::OnPgmInit()
|
||||||
{
|
{
|
||||||
PGM_BASE::BuildArgvUtf8();
|
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
|
wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
|
||||||
|
|
||||||
|
@ -319,60 +285,10 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
wxString pgm_name;
|
|
||||||
if( App().argc == 0 )
|
|
||||||
pgm_name = wxT( "kicad" );
|
|
||||||
else
|
|
||||||
pgm_name = wxFileName( App().argv[0] ).GetName().Lower();
|
|
||||||
|
|
||||||
argparse::ArgumentParser argParser( std::string( pgm_name.utf8_str() ), KICAD_MAJOR_MINOR_VERSION );
|
|
||||||
|
|
||||||
for(COMMAND_ENTRY& entry : commandStack)
|
|
||||||
{
|
|
||||||
argParser.add_subparser( entry.handler->GetArgParser() );
|
|
||||||
|
|
||||||
for( COMMAND_ENTRY& subentry : entry.subCommands )
|
|
||||||
{
|
|
||||||
entry.handler->GetArgParser().add_subparser( subentry.handler->GetArgParser() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
argParser.parse_args( m_argcUtf8, m_argvUtf8 );
|
|
||||||
}
|
|
||||||
catch( const std::runtime_error& )
|
|
||||||
{
|
|
||||||
// Ignore any argParser "errors"
|
|
||||||
// unforunately there are cases like the only arg being a file (double click open)
|
|
||||||
// that we need to fall through
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cliCmdRequested = false;
|
|
||||||
CLI::COMMAND* cliCmd = nullptr;
|
|
||||||
for( COMMAND_ENTRY& entry : commandStack )
|
|
||||||
{
|
|
||||||
if( argParser.is_subcommand_used( entry.handler->GetName() ) )
|
|
||||||
{
|
|
||||||
for( COMMAND_ENTRY& subentry : entry.subCommands )
|
|
||||||
{
|
|
||||||
if( entry.handler->GetArgParser().is_subcommand_used( subentry.handler->GetName() ) )
|
|
||||||
{
|
|
||||||
cliCmd = subentry.handler;
|
|
||||||
cliCmdRequested = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !cliCmdRequested )
|
|
||||||
{
|
|
||||||
cliCmd = entry.handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not all kicad applications use the python stuff. skip python init
|
// Not all kicad applications use the python stuff. skip python init
|
||||||
// for these apps.
|
// for these apps.
|
||||||
bool skip_python_initialization = cliCmdRequested;
|
bool skip_python_initialization = false;
|
||||||
#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) ||\
|
#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) ||\
|
||||||
defined( PCB_CALCULATOR_BUILD )
|
defined( PCB_CALCULATOR_BUILD )
|
||||||
skip_python_initialization = true;
|
skip_python_initialization = true;
|
||||||
|
@ -404,33 +320,13 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
||||||
Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
|
Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FRAME_T appType = TOP_FRAME;
|
|
||||||
|
|
||||||
// Tell the settings manager about the current Kiway
|
// Tell the settings manager about the current Kiway
|
||||||
GetSettingsManager().SetKiway( &Kiway );
|
GetSettingsManager().SetKiway( &Kiway );
|
||||||
|
|
||||||
if( cliCmdRequested )
|
|
||||||
{
|
|
||||||
int exitCode = CLI::EXIT_CODES::ERR_UNKNOWN;
|
|
||||||
if( cliCmd )
|
|
||||||
{
|
|
||||||
exitCode = cliCmd->Perform( Kiway );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( exitCode != CLI::EXIT_CODES::AVOID_CLOSING )
|
|
||||||
{
|
|
||||||
std::exit( exitCode );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use KIWAY to create a top window, which registers its existence also.
|
// Use KIWAY to create a top window, which registers its existence also.
|
||||||
// "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
|
// "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
|
||||||
// and is one of the types in FRAME_T.
|
// and is one of the types in FRAME_T.
|
||||||
KIWAY_PLAYER* frame = Kiway.Player( appType, true );
|
KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );
|
||||||
|
|
||||||
if( frame == nullptr )
|
if( frame == nullptr )
|
||||||
{
|
{
|
||||||
|
@ -453,7 +349,17 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
||||||
// Now after the frame processing, the rest of the positional args are files
|
// Now after the frame processing, the rest of the positional args are files
|
||||||
std::vector<wxString> fileArgs;
|
std::vector<wxString> fileArgs;
|
||||||
|
|
||||||
if( App().argc > 1 )
|
|
||||||
|
static const wxCmdLineEntryDesc desc[] = {
|
||||||
|
{ wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
|
||||||
|
wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
|
{ wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
wxCmdLineParser parser( App().argc, App().argv );
|
||||||
|
parser.SetDesc( desc );
|
||||||
|
parser.Parse( false );
|
||||||
|
if( parser.GetParamCount() )
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
gerbview handles multiple project data files, i.e. gerber files on
|
gerbview handles multiple project data files, i.e. gerber files on
|
||||||
|
@ -464,15 +370,15 @@ bool PGM_SINGLE_TOP::OnPgmInit()
|
||||||
launcher.
|
launcher.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for( int i = 1; i < App().argc; i++ )
|
for( size_t i = 0; i < parser.GetParamCount(); i++ )
|
||||||
fileArgs.push_back( App().argv[i] );
|
fileArgs.push_back( parser.GetParam( i ) );
|
||||||
|
|
||||||
// special attention to a single argument: argv[1] (==argSet[0])
|
// special attention to a single argument: argv[1] (==argSet[0])
|
||||||
if( fileArgs.size() == 1 )
|
if( fileArgs.size() == 1 )
|
||||||
{
|
{
|
||||||
wxFileName argv1( fileArgs[0] );
|
wxFileName argv1( fileArgs[0] );
|
||||||
|
|
||||||
#if defined( PGM_DATA_FILE_EXT )
|
#if defined(PGM_DATA_FILE_EXT)
|
||||||
// PGM_DATA_FILE_EXT, if present, may be different for each compile,
|
// PGM_DATA_FILE_EXT, if present, may be different for each compile,
|
||||||
// it may come from CMake on the compiler command line, but often does not.
|
// it may come from CMake on the compiler command line, but often does not.
|
||||||
// This facility is mostly useful for those program footprints
|
// This facility is mostly useful for those program footprints
|
||||||
|
|
|
@ -23,7 +23,6 @@ set( KICAD_SRCS
|
||||||
files-io.cpp
|
files-io.cpp
|
||||||
import_proj.cpp
|
import_proj.cpp
|
||||||
import_project.cpp
|
import_project.cpp
|
||||||
kicad.cpp
|
|
||||||
kicad_manager_frame.cpp
|
kicad_manager_frame.cpp
|
||||||
menubar.cpp
|
menubar.cpp
|
||||||
project_template.cpp
|
project_template.cpp
|
||||||
|
@ -57,11 +56,29 @@ if( APPLE )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable( kicad WIN32 MACOSX_BUNDLE
|
add_executable( kicad WIN32 MACOSX_BUNDLE
|
||||||
|
kicad.cpp
|
||||||
${KICAD_SRCS}
|
${KICAD_SRCS}
|
||||||
${KICAD_EXTRA_SRCS}
|
${KICAD_EXTRA_SRCS}
|
||||||
${KICAD_RESOURCES}
|
${KICAD_RESOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_executable( kicad-cli WIN32 MACOSX_BUNDLE
|
||||||
|
kicad_cli.cpp
|
||||||
|
${KICAD_SRCS}
|
||||||
|
${KICAD_EXTRA_SRCS}
|
||||||
|
${KICAD_RESOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
if( MSVC )
|
||||||
|
# The cli needs subsystem:console or else we can't link wmain/main
|
||||||
|
set_target_properties(kicad-cli PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
|
||||||
|
set_target_properties(kicad-cli PROPERTIES COMPILE_DEFINITIONS_RELWITHDEBINFO "_CONSOLE")
|
||||||
|
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||||
|
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||||
|
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||||
|
set_target_properties(kicad-cli PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||||
|
endif()
|
||||||
|
|
||||||
if( UNIX )
|
if( UNIX )
|
||||||
# for build directory: create kiface symlinks so kicad (exe) can be run in-situ
|
# for build directory: create kiface symlinks so kicad (exe) can be run in-situ
|
||||||
add_custom_target( kiface_sym_links
|
add_custom_target( kiface_sym_links
|
||||||
|
@ -81,6 +98,16 @@ if( APPLE )
|
||||||
common
|
common
|
||||||
${wxWidgets_LIBRARIES}
|
${wxWidgets_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_target_properties( kicad-cli PROPERTIES
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST ${PROJECT_BINARY_DIR}/kicad/Info.plist
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries( kicad-cli
|
||||||
|
nlohmann_json
|
||||||
|
common
|
||||||
|
${wxWidgets_LIBRARIES}
|
||||||
|
)
|
||||||
else()
|
else()
|
||||||
target_link_libraries( kicad
|
target_link_libraries( kicad
|
||||||
nlohmann_json
|
nlohmann_json
|
||||||
|
@ -89,15 +116,28 @@ else()
|
||||||
common #repeated due to a circular dependency between gal and common
|
common #repeated due to a circular dependency between gal and common
|
||||||
${wxWidgets_LIBRARIES}
|
${wxWidgets_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries( kicad-cli
|
||||||
|
nlohmann_json
|
||||||
|
common
|
||||||
|
gal
|
||||||
|
common #repeated due to a circular dependency between gal and common
|
||||||
|
${wxWidgets_LIBRARIES}
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries( kicad pcm )
|
target_link_libraries( kicad pcm )
|
||||||
|
target_link_libraries( kicad-cli pcm )
|
||||||
|
|
||||||
target_include_directories( kicad PRIVATE
|
target_include_directories( kicad PRIVATE
|
||||||
$<TARGET_PROPERTY:thread-pool,INTERFACE_INCLUDE_DIRECTORIES>
|
$<TARGET_PROPERTY:thread-pool,INTERFACE_INCLUDE_DIRECTORIES>
|
||||||
)
|
)
|
||||||
|
|
||||||
install( TARGETS kicad
|
target_include_directories( kicad-cli PRIVATE
|
||||||
|
$<TARGET_PROPERTY:thread-pool,INTERFACE_INCLUDE_DIRECTORIES>
|
||||||
|
)
|
||||||
|
|
||||||
|
install( TARGETS kicad kicad-cli
|
||||||
DESTINATION ${KICAD_BIN}
|
DESTINATION ${KICAD_BIN}
|
||||||
COMPONENT binary
|
COMPONENT binary
|
||||||
)
|
)
|
||||||
|
@ -107,14 +147,6 @@ if( KICAD_WIN32_INSTALL_PDBS )
|
||||||
install(FILES $<TARGET_PDB_FILE:kicad> DESTINATION ${KICAD_BIN})
|
install(FILES $<TARGET_PDB_FILE:kicad> DESTINATION ${KICAD_BIN})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if( WIN32 )
|
|
||||||
add_custom_command( TARGET kicad POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/resources/msw/cmd-wrappers/kicad.cmd" "$<TARGET_FILE_DIR:kicad>"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/resources/msw/cmd-wrappers/kicad.cmd" DESTINATION ${KICAD_BIN})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if( APPLE )
|
if( APPLE )
|
||||||
# "install( CODE ... )" will launch its own CMake, so no variables from
|
# "install( CODE ... )" will launch its own CMake, so no variables from
|
||||||
# this CMake instance are accessible... use helper to transfer
|
# this CMake instance are accessible... use helper to transfer
|
||||||
|
|
265
kicad/kicad.cpp
265
kicad/kicad.cpp
|
@ -33,6 +33,7 @@
|
||||||
#include <wx/app.h>
|
#include <wx/app.h>
|
||||||
#include <wx/stdpaths.h>
|
#include <wx/stdpaths.h>
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
#include <wx/cmdline.h>
|
||||||
|
|
||||||
#include <filehistory.h>
|
#include <filehistory.h>
|
||||||
#include <hotkeys_basic.h>
|
#include <hotkeys_basic.h>
|
||||||
|
@ -51,13 +52,9 @@
|
||||||
#include "pgm_kicad.h"
|
#include "pgm_kicad.h"
|
||||||
#include "kicad_manager_frame.h"
|
#include "kicad_manager_frame.h"
|
||||||
|
|
||||||
#include <kicad_build_version.h>
|
|
||||||
#include <kiplatform/app.h>
|
#include <kiplatform/app.h>
|
||||||
#include <kiplatform/environment.h>
|
#include <kiplatform/environment.h>
|
||||||
|
|
||||||
#include "cli/command_export_kicad_pcbnew.h"
|
|
||||||
#include "cli/command_export_step.h"
|
|
||||||
#include "cli/exit_codes.h"
|
|
||||||
|
|
||||||
// a dummy to quiet linking with EDA_BASE_FRAME::config();
|
// a dummy to quiet linking with EDA_BASE_FRAME::config();
|
||||||
#include <kiface_base.h>
|
#include <kiface_base.h>
|
||||||
|
@ -93,25 +90,9 @@ PGM_KICAD& PgmTop()
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct COMMAND_ENTRY
|
|
||||||
{
|
|
||||||
CLI::COMMAND* handler;
|
|
||||||
|
|
||||||
std::vector<COMMAND_ENTRY> subCommands;
|
|
||||||
|
|
||||||
COMMAND_ENTRY( CLI::COMMAND* aHandler ) : handler( aHandler ){};
|
|
||||||
COMMAND_ENTRY( CLI::COMMAND* aHandler, std::vector<COMMAND_ENTRY> aSub ) :
|
|
||||||
handler( aHandler ), subCommands( aSub ){};
|
|
||||||
};
|
|
||||||
|
|
||||||
static CLI::EXPORT_STEP_COMMAND stepCmd{};
|
|
||||||
static CLI::EXPORT_KICAD_PCBNEW_COMMAND exportPcbCmd{};
|
|
||||||
|
|
||||||
static std::vector<COMMAND_ENTRY> commandStack = { { &exportPcbCmd, { &stepCmd } } };
|
|
||||||
|
|
||||||
bool PGM_KICAD::OnPgmInit()
|
bool PGM_KICAD::OnPgmInit()
|
||||||
{
|
{
|
||||||
PGM_BASE::BuildArgvUtf8();
|
|
||||||
App().SetAppDisplayName( wxT( "KiCad" ) );
|
App().SetAppDisplayName( wxT( "KiCad" ) );
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
|
@ -124,54 +105,60 @@ bool PGM_KICAD::OnPgmInit()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
argparse::ArgumentParser argParser( std::string( "kicad" ),
|
static const wxCmdLineEntryDesc desc[] = {
|
||||||
KICAD_MAJOR_MINOR_VERSION );
|
{ wxCMD_LINE_OPTION, "f", "frame", "Frame to load", wxCMD_LINE_VAL_STRING, 0 },
|
||||||
|
{ wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
|
||||||
|
wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
|
{ wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
for( COMMAND_ENTRY& entry : commandStack )
|
wxCmdLineParser parser( App().argc, App().argv );
|
||||||
|
parser.SetDesc( desc );
|
||||||
|
parser.Parse( false );
|
||||||
|
|
||||||
|
FRAME_T appType = KICAD_MAIN_FRAME_T;
|
||||||
|
|
||||||
|
const struct
|
||||||
{
|
{
|
||||||
argParser.add_subparser( entry.handler->GetArgParser() );
|
wxString name;
|
||||||
|
FRAME_T type;
|
||||||
|
} frameTypes[] = { { wxT( "pcb" ), FRAME_PCB_EDITOR },
|
||||||
|
{ wxT( "fpedit" ), FRAME_FOOTPRINT_EDITOR },
|
||||||
|
{ wxT( "sch" ), FRAME_SCH },
|
||||||
|
{ wxT( "calc" ), FRAME_CALC },
|
||||||
|
{ wxT( "bm2cmp" ), FRAME_BM2CMP },
|
||||||
|
{ wxT( "ds" ), FRAME_PL_EDITOR },
|
||||||
|
{ wxT( "gerb" ), FRAME_GERBER },
|
||||||
|
{ wxT( "" ), FRAME_T_COUNT } };
|
||||||
|
|
||||||
for( COMMAND_ENTRY& subentry : entry.subCommands )
|
wxString frameName;
|
||||||
|
|
||||||
|
if( parser.Found( "frame", &frameName ) )
|
||||||
|
{
|
||||||
|
appType = FRAME_T_COUNT;
|
||||||
|
|
||||||
|
for( const auto& it : frameTypes )
|
||||||
{
|
{
|
||||||
entry.handler->GetArgParser().add_subparser( subentry.handler->GetArgParser() );
|
if( it.name == frameName )
|
||||||
|
appType = it.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( appType == FRAME_T_COUNT )
|
||||||
|
{
|
||||||
|
wxLogError( wxT( "Unknown frame: %s" ), frameName );
|
||||||
|
// Clean up
|
||||||
|
OnPgmExit();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
bool skipPythonInit = false;
|
||||||
{
|
|
||||||
argParser.parse_args( m_argcUtf8, m_argvUtf8 );
|
|
||||||
}
|
|
||||||
catch( const std::runtime_error& err )
|
|
||||||
{
|
|
||||||
// Ignore any argParser "errors"
|
|
||||||
// unforunately there are cases like the only arg being a file (double click open)
|
|
||||||
// that we need to fall through
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cliCmdRequested = false;
|
if( appType == FRAME_BM2CMP || appType == FRAME_PL_EDITOR || appType == FRAME_GERBER
|
||||||
CLI::COMMAND* cliCmd = nullptr;
|
|| appType == FRAME_CALC )
|
||||||
for( COMMAND_ENTRY& entry : commandStack )
|
skipPythonInit = true;
|
||||||
{
|
|
||||||
if( argParser.is_subcommand_used( entry.handler->GetName() ) )
|
|
||||||
{
|
|
||||||
for( COMMAND_ENTRY& subentry : entry.subCommands )
|
|
||||||
{
|
|
||||||
if( entry.handler->GetArgParser().is_subcommand_used(
|
|
||||||
subentry.handler->GetName() ) )
|
|
||||||
{
|
|
||||||
cliCmd = subentry.handler;
|
|
||||||
cliCmdRequested = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !cliCmdRequested )
|
if( !InitPgm( false, skipPythonInit ) )
|
||||||
{
|
|
||||||
cliCmd = entry.handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !InitPgm() )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_bm.InitSettings( new KICAD_SETTINGS );
|
m_bm.InitSettings( new KICAD_SETTINGS );
|
||||||
|
@ -215,76 +202,142 @@ bool PGM_KICAD::OnPgmInit()
|
||||||
m_bm.m_search.Insert( it->second.GetValue(), 0 );
|
m_bm.m_search.Insert( it->second.GetValue(), 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cliCmdRequested )
|
wxFrame* frame = nullptr;
|
||||||
{
|
KIWAY_PLAYER* playerFrame = nullptr;
|
||||||
int exitCode = CLI::EXIT_CODES::ERR_UNKNOWN;
|
KICAD_MANAGER_FRAME* managerFrame = nullptr;
|
||||||
if( cliCmd )
|
|
||||||
{
|
|
||||||
exitCode = cliCmd->Perform( Kiway );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( exitCode != CLI::EXIT_CODES::AVOID_CLOSING )
|
if( appType == KICAD_MAIN_FRAME_T )
|
||||||
|
{
|
||||||
|
managerFrame = new KICAD_MANAGER_FRAME( nullptr, wxT( "KiCad" ), wxDefaultPosition,
|
||||||
|
wxSize( 775, -1 ) );
|
||||||
|
frame = managerFrame;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use KIWAY to create a top window, which registers its existence also.
|
||||||
|
// "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
|
||||||
|
// and is one of the types in FRAME_T.
|
||||||
|
playerFrame = Kiway.Player( appType, true );
|
||||||
|
frame = playerFrame;
|
||||||
|
|
||||||
|
if( frame == nullptr )
|
||||||
{
|
{
|
||||||
std::exit( exitCode );
|
return false;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KICAD_MANAGER_FRAME* frame = new KICAD_MANAGER_FRAME( nullptr, wxT( "KiCad" ),
|
|
||||||
wxDefaultPosition, wxSize( 775, -1 ) );
|
|
||||||
App().SetTopWindow( frame );
|
App().SetTopWindow( frame );
|
||||||
|
|
||||||
|
if( playerFrame )
|
||||||
|
App().SetAppDisplayName( playerFrame->GetAboutTitle() );
|
||||||
|
|
||||||
Kiway.SetTop( frame );
|
Kiway.SetTop( frame );
|
||||||
|
|
||||||
KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
|
KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
|
||||||
|
|
||||||
wxString projToLoad;
|
wxString projToLoad;
|
||||||
|
|
||||||
if( App().argc > 1 )
|
|
||||||
|
if( playerFrame && parser.GetParamCount() )
|
||||||
{
|
{
|
||||||
wxFileName tmp = App().argv[1];
|
// Now after the frame processing, the rest of the positional args are files
|
||||||
|
std::vector<wxString> fileArgs;
|
||||||
|
/*
|
||||||
|
gerbview handles multiple project data files, i.e. gerber files on
|
||||||
|
cmd line. Others currently do not, they handle only one. For common
|
||||||
|
code simplicity we simply pass all the arguments in however, each
|
||||||
|
program module can do with them what they want, ignore, complain
|
||||||
|
whatever. We don't establish policy here, as this is a multi-purpose
|
||||||
|
launcher.
|
||||||
|
*/
|
||||||
|
|
||||||
if( tmp.GetExt() != ProjectFileExtension && tmp.GetExt() != LegacyProjectFileExtension )
|
for( size_t i = 0; i < parser.GetParamCount(); i++ )
|
||||||
|
fileArgs.push_back( parser.GetParam( i ) );
|
||||||
|
|
||||||
|
// special attention to a single argument: argv[1] (==argSet[0])
|
||||||
|
if( fileArgs.size() == 1 )
|
||||||
{
|
{
|
||||||
wxString msg;
|
wxFileName argv1( fileArgs[0] );
|
||||||
|
|
||||||
msg.Printf( _( "File '%s'\ndoes not appear to be a valid KiCad project file." ),
|
#if defined( PGM_DATA_FILE_EXT )
|
||||||
tmp.GetFullPath() );
|
// PGM_DATA_FILE_EXT, if present, may be different for each compile,
|
||||||
wxMessageDialog dlg( nullptr, msg, _( "Error" ), wxOK | wxICON_EXCLAMATION );
|
// it may come from CMake on the compiler command line, but often does not.
|
||||||
dlg.ShowModal();
|
// This facility is mostly useful for those program footprints
|
||||||
|
// supporting a single argv[1].
|
||||||
|
if( !argv1.GetExt() )
|
||||||
|
argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
|
||||||
|
#endif
|
||||||
|
argv1.MakeAbsolute();
|
||||||
|
|
||||||
|
fileArgs[0] = argv1.GetFullPath();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Use the KIWAY_PLAYER::OpenProjectFiles() API function:
|
||||||
|
if( !playerFrame->OpenProjectFiles( fileArgs ) )
|
||||||
{
|
{
|
||||||
projToLoad = tmp.GetFullPath();
|
// OpenProjectFiles() API asks that it report failure to the UI.
|
||||||
|
// Nothing further to say here.
|
||||||
|
|
||||||
|
// We've already initialized things at this point, but wx won't call OnExit if
|
||||||
|
// we fail out. Call our own cleanup routine here to ensure the relevant resources
|
||||||
|
// are freed at the right time (if they aren't, segfaults will occur).
|
||||||
|
OnPgmExit();
|
||||||
|
|
||||||
|
// Fail the process startup if the file could not be opened,
|
||||||
|
// although this is an optional choice, one that can be reversed
|
||||||
|
// also in the KIFACE specific OpenProjectFiles() return value.
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( managerFrame )
|
||||||
// If no file was given as an argument, check that there was a file open.
|
|
||||||
if( projToLoad.IsEmpty() && settings->m_OpenProjects.size() )
|
|
||||||
{
|
{
|
||||||
wxString last_pro = settings->m_OpenProjects.front();
|
if( App().argc > 1 )
|
||||||
settings->m_OpenProjects.erase( settings->m_OpenProjects.begin() );
|
|
||||||
|
|
||||||
if( wxFileExists( last_pro ) )
|
|
||||||
{
|
{
|
||||||
// Try to open the last opened project,
|
wxFileName tmp = App().argv[1];
|
||||||
// if a project name is not given when starting Kicad
|
|
||||||
projToLoad = last_pro;
|
if( tmp.GetExt() != ProjectFileExtension && tmp.GetExt() != LegacyProjectFileExtension )
|
||||||
|
{
|
||||||
|
wxString msg;
|
||||||
|
|
||||||
|
msg.Printf( _( "File '%s'\ndoes not appear to be a valid KiCad project file." ),
|
||||||
|
tmp.GetFullPath() );
|
||||||
|
wxMessageDialog dlg( nullptr, msg, _( "Error" ), wxOK | wxICON_EXCLAMATION );
|
||||||
|
dlg.ShowModal();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
projToLoad = tmp.GetFullPath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Do not attempt to load a non-existent project file.
|
// If no file was given as an argument, check that there was a file open.
|
||||||
if( !projToLoad.empty() )
|
if( projToLoad.IsEmpty() && settings->m_OpenProjects.size() )
|
||||||
{
|
|
||||||
wxFileName fn( projToLoad );
|
|
||||||
|
|
||||||
if( fn.Exists() )
|
|
||||||
{
|
{
|
||||||
fn.MakeAbsolute();
|
wxString last_pro = settings->m_OpenProjects.front();
|
||||||
frame->LoadProject( fn );
|
settings->m_OpenProjects.erase( settings->m_OpenProjects.begin() );
|
||||||
|
|
||||||
|
if( wxFileExists( last_pro ) )
|
||||||
|
{
|
||||||
|
// Try to open the last opened project,
|
||||||
|
// if a project name is not given when starting Kicad
|
||||||
|
projToLoad = last_pro;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not attempt to load a non-existent project file.
|
||||||
|
if( !projToLoad.empty() )
|
||||||
|
{
|
||||||
|
wxFileName fn( projToLoad );
|
||||||
|
|
||||||
|
if( fn.Exists() )
|
||||||
|
{
|
||||||
|
fn.MakeAbsolute();
|
||||||
|
|
||||||
|
if( appType == KICAD_MAIN_FRAME_T )
|
||||||
|
{
|
||||||
|
managerFrame->LoadProject( fn );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,6 +348,12 @@ bool PGM_KICAD::OnPgmInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PGM_KICAD::OnPgmRun()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PGM_KICAD::OnPgmExit()
|
void PGM_KICAD::OnPgmExit()
|
||||||
{
|
{
|
||||||
Kiway.OnKiwayEnd();
|
Kiway.OnKiwayEnd();
|
||||||
|
|
|
@ -0,0 +1,432 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||||
|
* Copyright (C) 2004-2021 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 Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file kicad.cpp
|
||||||
|
* Main KiCad project manager file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <wx/filename.h>
|
||||||
|
#include <wx/log.h>
|
||||||
|
#include <wx/app.h>
|
||||||
|
#include <wx/stdpaths.h>
|
||||||
|
#include <wx/msgdlg.h>
|
||||||
|
|
||||||
|
#include <kiway.h>
|
||||||
|
#include <macros.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <settings/settings_manager.h>
|
||||||
|
#include <settings/kicad_settings.h>
|
||||||
|
#include <systemdirsappend.h>
|
||||||
|
#include <trace_helpers.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "pgm_kicad.h"
|
||||||
|
#include "kicad_manager_frame.h"
|
||||||
|
|
||||||
|
#include <kicad_build_version.h>
|
||||||
|
#include <kiplatform/app.h>
|
||||||
|
#include <kiplatform/environment.h>
|
||||||
|
|
||||||
|
#include "cli/command_pcb.h"
|
||||||
|
#include "cli/command_pcb_export.h"
|
||||||
|
#include "cli/command_export_pcb_svg.h"
|
||||||
|
#include "cli/command_export_step.h"
|
||||||
|
#include "cli/exit_codes.h"
|
||||||
|
|
||||||
|
// a dummy to quiet linking with EDA_BASE_FRAME::config();
|
||||||
|
#include <kiface_base.h>
|
||||||
|
KIFACE_BASE& Kiface()
|
||||||
|
{
|
||||||
|
// This function should never be called. It is only referenced from
|
||||||
|
// EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
|
||||||
|
// not to be actually called.
|
||||||
|
wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
|
||||||
|
|
||||||
|
throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PGM_KICAD program;
|
||||||
|
|
||||||
|
|
||||||
|
PGM_BASE& Pgm()
|
||||||
|
{
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from a python script.
|
||||||
|
PGM_BASE* PgmOrNull()
|
||||||
|
{
|
||||||
|
return &program;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PGM_KICAD& PgmTop()
|
||||||
|
{
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct COMMAND_ENTRY
|
||||||
|
{
|
||||||
|
CLI::COMMAND* handler;
|
||||||
|
|
||||||
|
std::vector<COMMAND_ENTRY> subCommands;
|
||||||
|
|
||||||
|
COMMAND_ENTRY( CLI::COMMAND* aHandler ) : handler( aHandler ){};
|
||||||
|
COMMAND_ENTRY( CLI::COMMAND* aHandler, std::vector<COMMAND_ENTRY> aSub ) :
|
||||||
|
handler( aHandler ), subCommands( aSub ){};
|
||||||
|
};
|
||||||
|
|
||||||
|
static CLI::EXPORT_STEP_COMMAND stepCmd{};
|
||||||
|
static CLI::EXPORT_PCB_SVG_COMMAND svgCmd{};
|
||||||
|
static CLI::EXPORT_PCB_COMMAND exportPcbCmd{};
|
||||||
|
static CLI::PCB_COMMAND pcbCmd{};
|
||||||
|
|
||||||
|
static std::vector<COMMAND_ENTRY> commandStack = {
|
||||||
|
{
|
||||||
|
&pcbCmd,
|
||||||
|
{
|
||||||
|
{ &exportPcbCmd,
|
||||||
|
{
|
||||||
|
&stepCmd,
|
||||||
|
&svgCmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void recurseArgParserBuild( argparse::ArgumentParser& aArgParser, COMMAND_ENTRY& aEntry )
|
||||||
|
{
|
||||||
|
aArgParser.add_subparser( aEntry.handler->GetArgParser() );
|
||||||
|
|
||||||
|
for( COMMAND_ENTRY& subEntry : aEntry.subCommands )
|
||||||
|
{
|
||||||
|
recurseArgParserBuild( aEntry.handler->GetArgParser(), subEntry );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static COMMAND_ENTRY* recurseArgParserSubCommandUsed( argparse::ArgumentParser& aArgParser,
|
||||||
|
COMMAND_ENTRY& aEntry )
|
||||||
|
{
|
||||||
|
COMMAND_ENTRY* cliCmd = nullptr;
|
||||||
|
|
||||||
|
if( aArgParser.is_subcommand_used( aEntry.handler->GetName() ) )
|
||||||
|
{
|
||||||
|
for( COMMAND_ENTRY& subentry : aEntry.subCommands )
|
||||||
|
{
|
||||||
|
cliCmd = recurseArgParserSubCommandUsed( aEntry.handler->GetArgParser(), subentry );
|
||||||
|
if( cliCmd )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!cliCmd)
|
||||||
|
cliCmd = &aEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cliCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PGM_KICAD::OnPgmInit()
|
||||||
|
{
|
||||||
|
PGM_BASE::BuildArgvUtf8();
|
||||||
|
App().SetAppDisplayName( wxT( "KiCad" ) );
|
||||||
|
|
||||||
|
#if defined( DEBUG )
|
||||||
|
wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
|
||||||
|
|
||||||
|
if( !wxIsAbsolutePath( absoluteArgv0 ) )
|
||||||
|
{
|
||||||
|
wxLogError( wxT( "No meaningful argv[0]" ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( !InitPgm( true, true) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_bm.InitSettings( new KICAD_SETTINGS );
|
||||||
|
GetSettingsManager().RegisterSettings( PgmSettings() );
|
||||||
|
GetSettingsManager().SetKiway( &Kiway );
|
||||||
|
m_bm.Init();
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PGM_KICAD::OnPgmRun()
|
||||||
|
{
|
||||||
|
argparse::ArgumentParser argParser( std::string( "kicad-cli" ), KICAD_MAJOR_MINOR_VERSION );
|
||||||
|
|
||||||
|
for( COMMAND_ENTRY& entry : commandStack )
|
||||||
|
{
|
||||||
|
recurseArgParserBuild( argParser, entry );
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
argParser.parse_args( m_argcUtf8, m_argvUtf8 );
|
||||||
|
}
|
||||||
|
catch( const std::runtime_error& err )
|
||||||
|
{
|
||||||
|
std::cout << err.what() << std::endl;
|
||||||
|
std::cout << argParser;
|
||||||
|
return CLI::EXIT_CODES::ERR_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_ENTRY* cliCmd = nullptr;
|
||||||
|
for( COMMAND_ENTRY& entry : commandStack )
|
||||||
|
{
|
||||||
|
if( argParser.is_subcommand_used( entry.handler->GetName() ) )
|
||||||
|
{
|
||||||
|
cliCmd = recurseArgParserSubCommandUsed( argParser, entry );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( cliCmd )
|
||||||
|
{
|
||||||
|
int exitCode = CLI::EXIT_CODES::ERR_UNKNOWN;
|
||||||
|
if( cliCmd )
|
||||||
|
{
|
||||||
|
exitCode = cliCmd->handler->Perform( Kiway );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( exitCode != CLI::EXIT_CODES::AVOID_CLOSING )
|
||||||
|
{
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << argParser;
|
||||||
|
return CLI::EXIT_CODES::ERR_ARGS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PGM_KICAD::OnPgmExit()
|
||||||
|
{
|
||||||
|
Kiway.OnKiwayEnd();
|
||||||
|
|
||||||
|
if( m_settings_manager && m_settings_manager->IsOK() )
|
||||||
|
{
|
||||||
|
SaveCommonSettings();
|
||||||
|
m_settings_manager->Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy everything in PGM_KICAD,
|
||||||
|
// especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
|
||||||
|
// than static destruction would.
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PGM_KICAD::MacOpenFile( const wxString& aFileName )
|
||||||
|
{
|
||||||
|
#if defined( __WXMAC__ )
|
||||||
|
|
||||||
|
KICAD_MANAGER_FRAME* frame = (KICAD_MANAGER_FRAME*) App().GetTopWindow();
|
||||||
|
|
||||||
|
if( !aFileName.empty() && wxFileExists( aFileName ) )
|
||||||
|
frame->LoadProject( wxFileName( aFileName ) );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PGM_KICAD::Destroy()
|
||||||
|
{
|
||||||
|
// unlike a normal destructor, this is designed to be called more
|
||||||
|
// than once safely:
|
||||||
|
|
||||||
|
m_bm.End();
|
||||||
|
|
||||||
|
PGM_BASE::Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KIWAY Kiway( &Pgm(), KFCTL_CPP_PROJECT_SUITE );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not publicly visible because most of the action is in #PGM_KICAD these days.
|
||||||
|
*/
|
||||||
|
struct APP_KICAD_CLI : public wxAppConsole
|
||||||
|
{
|
||||||
|
APP_KICAD_CLI() : wxAppConsole()
|
||||||
|
{
|
||||||
|
// Init the environment each platform wants
|
||||||
|
KIPLATFORM::ENV::Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OnInit() override
|
||||||
|
{
|
||||||
|
// Perform platform-specific init tasks
|
||||||
|
if( !KIPLATFORM::APP::Init() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !program.OnPgmInit() )
|
||||||
|
{
|
||||||
|
program.OnPgmExit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OnExit() override
|
||||||
|
{
|
||||||
|
program.OnPgmExit();
|
||||||
|
|
||||||
|
#if defined( __FreeBSD__ )
|
||||||
|
// Avoid wxLog crashing when used in destructors.
|
||||||
|
wxLog::EnableLogging( false );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return wxAppConsole::OnExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
int OnRun() override
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return program.OnPgmRun();
|
||||||
|
}
|
||||||
|
catch( const std::exception& e )
|
||||||
|
{
|
||||||
|
wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
|
||||||
|
FROM_UTF8( typeid( e ).name() ), FROM_UTF8( e.what() ) );
|
||||||
|
}
|
||||||
|
catch( const IO_ERROR& ioe )
|
||||||
|
{
|
||||||
|
wxLogError( ioe.What() );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
wxLogError( wxT( "Unhandled exception of unknown type" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FilterEvent( wxEvent& aEvent ) override
|
||||||
|
{
|
||||||
|
if( aEvent.GetEventType() == wxEVT_SHOW )
|
||||||
|
{
|
||||||
|
wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
|
||||||
|
wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
|
||||||
|
|
||||||
|
if( dialog && dialog->IsModal() )
|
||||||
|
Pgm().m_ModalDialogCount += event.IsShown() ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Event_Skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined( DEBUG )
|
||||||
|
/**
|
||||||
|
* Process any unhandled events at the application level.
|
||||||
|
*/
|
||||||
|
bool ProcessEvent( wxEvent& aEvent ) override
|
||||||
|
{
|
||||||
|
if( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
|
||||||
|
{
|
||||||
|
wxKeyEvent* keyEvent = static_cast<wxKeyEvent*>( &aEvent );
|
||||||
|
|
||||||
|
if( keyEvent )
|
||||||
|
{
|
||||||
|
wxLogTrace( kicadTraceKeyEvent, "APP_KICAD::ProcessEvent %s", dump( *keyEvent ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aEvent.Skip();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override main loop exception handling on debug builds.
|
||||||
|
*
|
||||||
|
* It can be painfully difficult to debug exceptions that happen in wxUpdateUIEvent
|
||||||
|
* handlers. The override provides a bit more useful information about the exception
|
||||||
|
* and a breakpoint can be set to pin point the event where the exception was thrown.
|
||||||
|
*/
|
||||||
|
bool OnExceptionInMainLoop() override
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch( const std::exception& e )
|
||||||
|
{
|
||||||
|
wxLogError( "Unhandled exception class: %s what: %s", FROM_UTF8( typeid( e ).name() ),
|
||||||
|
FROM_UTF8( e.what() ) );
|
||||||
|
}
|
||||||
|
catch( const IO_ERROR& ioe )
|
||||||
|
{
|
||||||
|
wxLogError( ioe.What() );
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
wxLogError( "Unhandled exception of unknown type" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // continue on. Return false to abort program
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set MacOS file associations.
|
||||||
|
*
|
||||||
|
* @see http://wiki.wxwidgets.org/WxMac-specific_topics
|
||||||
|
*/
|
||||||
|
#if defined( __WXMAC__ )
|
||||||
|
void MacOpenFile( const wxString& aFileName ) override
|
||||||
|
{
|
||||||
|
Pgm().MacOpenFile( aFileName );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_APP_CONSOLE( APP_KICAD_CLI )
|
||||||
|
|
||||||
|
|
||||||
|
// The C++ project manager supports one open PROJECT, so Prj() calls within
|
||||||
|
// this link image need this function.
|
||||||
|
PROJECT& Prj()
|
||||||
|
{
|
||||||
|
return Kiway.Prj();
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ public:
|
||||||
|
|
||||||
bool OnPgmInit();
|
bool OnPgmInit();
|
||||||
void OnPgmExit();
|
void OnPgmExit();
|
||||||
|
int OnPgmRun();
|
||||||
|
|
||||||
void MacOpenFile( const wxString& aFileName ) override;
|
void MacOpenFile( const wxString& aFileName ) override;
|
||||||
|
|
||||||
|
|
|
@ -756,12 +756,6 @@ if( WIN32 )
|
||||||
add_custom_command( TARGET pcbnew POST_BUILD
|
add_custom_command( TARGET pcbnew POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:kicad_3dsg>" "$<TARGET_FILE_DIR:pcbnew>"
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:kicad_3dsg>" "$<TARGET_FILE_DIR:pcbnew>"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command( TARGET pcbnew POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/resources/msw/cmd-wrappers/pcbnew.cmd" "$<TARGET_FILE_DIR:pcbnew>"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES "${CMAKE_SOURCE_DIR}/resources/msw/cmd-wrappers/pcbnew.cmd" DESTINATION ${KICAD_BIN})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# these 2 binaries are a matched set, keep them together:
|
# these 2 binaries are a matched set, keep them together:
|
||||||
|
|
|
@ -380,17 +380,24 @@ void DIALOG_EXPORT_STEP::onExportButton( wxCommandEvent& aEvent )
|
||||||
appK2S.AppendDir( wxT( ".." ) );
|
appK2S.AppendDir( wxT( ".." ) );
|
||||||
appK2S.AppendDir( wxT( "MacOS" ) );
|
appK2S.AppendDir( wxT( "MacOS" ) );
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
|
||||||
|
{
|
||||||
|
fn.RemoveLastDir();
|
||||||
|
fn.AppendDir( "kicad" );
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
appK2S.SetName( wxT( "pcbnew" ) );
|
|
||||||
|
appK2S.SetName( wxT( "kicad-cli" ) );
|
||||||
|
|
||||||
wxString cmdK2S = wxT( "\"" );
|
wxString cmdK2S = wxT( "\"" );
|
||||||
cmdK2S.Append( appK2S.GetFullPath() );
|
cmdK2S.Append( appK2S.GetFullPath() );
|
||||||
cmdK2S.Append( wxT( "\"" ) );
|
cmdK2S.Append( wxT( "\"" ) );
|
||||||
|
|
||||||
|
cmdK2S.Append( wxT( " pcb" ) );
|
||||||
cmdK2S.Append( wxT( " export" ) );
|
cmdK2S.Append( wxT( " export" ) );
|
||||||
cmdK2S.Append( wxT( " step" ) );
|
cmdK2S.Append( wxT( " step" ) );
|
||||||
cmdK2S.Append( wxT( " --gui" ) );
|
|
||||||
|
|
||||||
if( GetNoVirtOption() )
|
if( GetNoVirtOption() )
|
||||||
cmdK2S.Append( wxT( " --no-virtual" ) );
|
cmdK2S.Append( wxT( " --no-virtual" ) );
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
@"%~dp0kicad.exe" %*
|
|
|
@ -1 +0,0 @@
|
||||||
@"%~dp0pcbnew.exe" %*
|
|
Loading…
Reference in New Issue