Switching to python build script.
This commit is contained in:
parent
2f1965082c
commit
b56b262116
|
@ -0,0 +1,22 @@
|
|||
# Make Travis use docker (for faster builds, in theory)
|
||||
sudo: false
|
||||
|
||||
language: cpp
|
||||
compiler:
|
||||
- clang
|
||||
# - gcc
|
||||
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
|
||||
# Run setup to build ninja/gyp/etc and actually build xenia.
|
||||
before_script:
|
||||
- travis_retry ./xenia-build setup
|
||||
- ./xenia-build build --config=debug
|
||||
|
||||
# Run test suites.
|
||||
script:
|
||||
- ./xenia-build lint --all
|
||||
- ./xenia-build test --config=debug --no-build -- --enable_haswell_instructions=false
|
||||
- ./xenia-build test --config=debug --no-build -- --enable_haswell_instructions=true
|
|
@ -45,7 +45,7 @@ Windows 8.1+ with Python 2.7 and [Visual Studio 2015](https://www.visualstudio.c
|
|||
# Build on command line:
|
||||
> xb build
|
||||
# Run premake and open Visual Studio (run the 'xenia-app' project):
|
||||
> xb edit
|
||||
> xb devenv
|
||||
# Run premake to update the sln/vcproj's:
|
||||
> xb premake
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ff0bab3c8e3579684b0a5634d97f181bca8d0543
|
||||
Subproject commit 13552a8942c1fa5527e80698516912ad08d9e1ab
|
|
@ -46,12 +46,18 @@ void AttachConsole() {
|
|||
setvbuf(stderr, nullptr, _IONBF, 0);
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
||||
// Used in console mode apps; automatically picked based on subsystem.
|
||||
int main(int argc, wchar_t* argv[]) {
|
||||
int Main() {
|
||||
auto entry_info = xe::GetEntryInfo();
|
||||
|
||||
// Convert command line to an argv-like format so we can share code/use
|
||||
// gflags.
|
||||
auto command_line = GetCommandLineW();
|
||||
int argc;
|
||||
wchar_t** argv = CommandLineToArgvW(command_line, &argc);
|
||||
if (!argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
google::SetUsageMessage(std::string("usage: ") +
|
||||
xe::to_string(entry_info.usage));
|
||||
google::SetVersionString("1.0");
|
||||
|
@ -82,30 +88,23 @@ int main(int argc, wchar_t* argv[]) {
|
|||
int result = entry_info.entry_point(args);
|
||||
|
||||
google::ShutDownCommandLineFlags();
|
||||
LocalFree(argv);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
||||
// Used in console mode apps; automatically picked based on subsystem.
|
||||
int main(int argc_ignored, char** argv_ignored) { return xe::Main(); }
|
||||
|
||||
// Used in windowed apps; automatically picked based on subsystem.
|
||||
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR command_line, int) {
|
||||
// Attach a console so we can write output to stdout. If the user hasn't
|
||||
// redirected output themselves it'll pop up a window.
|
||||
xe::AttachConsole();
|
||||
|
||||
auto entry_info = xe::GetEntryInfo();
|
||||
|
||||
// Convert to an argv-like format so we can share code/use gflags.
|
||||
std::wstring buffer = entry_info.name + L" " + command_line;
|
||||
int argc;
|
||||
wchar_t** argv = CommandLineToArgvW(buffer.c_str(), &argc);
|
||||
if (!argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Run normal entry point.
|
||||
int result = main(argc, argv);
|
||||
|
||||
LocalFree(argv);
|
||||
return result;
|
||||
return xe::Main();
|
||||
}
|
||||
|
||||
#if defined _M_IX86
|
||||
|
|
|
@ -62,22 +62,12 @@ LPSYMGETSYMFROMADDR64 sym_get_sym_from_addr_64_ = nullptr;
|
|||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
class Win32StackWalker : public StackWalker {
|
||||
public:
|
||||
Win32StackWalker(backend::CodeCache* code_cache) {
|
||||
// Get the boundaries of the code cache so we can quickly tell if a symbol
|
||||
// is ours or not.
|
||||
// We store these globally so that the Sym* callbacks can access them.
|
||||
// They never change, so it's fine even if they are touched from multiple
|
||||
// threads.
|
||||
code_cache_ = code_cache;
|
||||
code_cache_min_ = code_cache_->base_address();
|
||||
code_cache_max_ = code_cache_->base_address() + code_cache_->total_size();
|
||||
bool InitializeStackWalker() {
|
||||
if (sym_get_options_) {
|
||||
// Already initialized.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Initialize() {
|
||||
std::lock_guard<std::mutex> lock(dbghelp_mutex_);
|
||||
|
||||
// Attempt to load dbghelp.
|
||||
// NOTE: we never free it. That's fine.
|
||||
HMODULE module = LoadLibrary(TEXT("dbghelp.dll"));
|
||||
|
@ -93,8 +83,7 @@ class Win32StackWalker : public StackWalker {
|
|||
GetProcAddress(module, "SymInitialize"));
|
||||
stack_walk_64_ =
|
||||
reinterpret_cast<LPSTACKWALK64>(GetProcAddress(module, "StackWalk64"));
|
||||
sym_function_table_access_64_ =
|
||||
reinterpret_cast<LPSYMFUNCTIONTABLEACCESS64>(
|
||||
sym_function_table_access_64_ = reinterpret_cast<LPSYMFUNCTIONTABLEACCESS64>(
|
||||
GetProcAddress(module, "SymFunctionTableAccess64"));
|
||||
sym_get_module_base_64_ = reinterpret_cast<LPSYMGETMODULEBASE64>(
|
||||
GetProcAddress(module, "SymGetModuleBase64"));
|
||||
|
@ -124,6 +113,24 @@ class Win32StackWalker : public StackWalker {
|
|||
return true;
|
||||
}
|
||||
|
||||
class Win32StackWalker : public StackWalker {
|
||||
public:
|
||||
Win32StackWalker(backend::CodeCache* code_cache) {
|
||||
// Get the boundaries of the code cache so we can quickly tell if a symbol
|
||||
// is ours or not.
|
||||
// We store these globally so that the Sym* callbacks can access them.
|
||||
// They never change, so it's fine even if they are touched from multiple
|
||||
// threads.
|
||||
code_cache_ = code_cache;
|
||||
code_cache_min_ = code_cache_->base_address();
|
||||
code_cache_max_ = code_cache_->base_address() + code_cache_->total_size();
|
||||
}
|
||||
|
||||
bool Initialize() {
|
||||
std::lock_guard<std::mutex> lock(dbghelp_mutex_);
|
||||
return InitializeStackWalker();
|
||||
}
|
||||
|
||||
size_t CaptureStackTrace(uint64_t* frame_host_pcs, size_t frame_offset,
|
||||
size_t frame_count,
|
||||
uint64_t* out_stack_hash) override {
|
||||
|
|
737
xb.bat
737
xb.bat
|
@ -3,22 +3,9 @@ REM Copyright 2015 Ben Vanik. All Rights Reserved.
|
|||
|
||||
SET DIR=%~dp0
|
||||
|
||||
SET XENIA_SLN=build\xenia.sln
|
||||
|
||||
SET VS14_VCVARSALL="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
SET VS15_VCVARSALL="C:\Program Files (x86)\Microsoft Visual Studio 15.0\VC\vcvarsall.bat"
|
||||
|
||||
REM ============================================================================
|
||||
REM Environment Validation
|
||||
REM ============================================================================
|
||||
REM To make life easier we just require everything before we try running.
|
||||
|
||||
CALL :check_git
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO ERROR:
|
||||
ECHO git must be installed and on PATH.
|
||||
GOTO :exit_error
|
||||
)
|
||||
|
||||
CALL :check_python
|
||||
IF %_RESULT% NEQ 0 (
|
||||
|
@ -28,672 +15,13 @@ IF %_RESULT% NEQ 0 (
|
|||
GOTO :exit_error
|
||||
)
|
||||
|
||||
CALL :check_msvc
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO ERROR:
|
||||
ECHO Visual Studio 2015 must be installed.
|
||||
ECHO.
|
||||
ECHO The Community Edition is free and can be downloaded here:
|
||||
ECHO https://www.visualstudio.com/downloads/visual-studio-2015-downloads-vs
|
||||
ECHO.
|
||||
ECHO Once installed, launch the 'Developer Command Prompt for VS2015' and run
|
||||
ECHO this script again.
|
||||
GOTO :exit_error
|
||||
)
|
||||
1>NUL 2>NUL CMD /c where devenv
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
CALL %VS14_VCVARSALL% amd64
|
||||
)
|
||||
|
||||
SET CLANG_FORMAT=""
|
||||
SET LLVM_CLANG_FORMAT="C:\Program Files (x86)\LLVM\bin\clang-format.exe"
|
||||
IF EXIST %LLVM_CLANG_FORMAT% (
|
||||
SET CLANG_FORMAT=%LLVM_CLANG_FORMAT%
|
||||
) ELSE (
|
||||
1>NUL 2>NUL CMD /c where clang-format
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
SET CLANG_FORMAT="clang-format"
|
||||
)
|
||||
)
|
||||
|
||||
REM ============================================================================
|
||||
REM Command Parsing
|
||||
REM Trampoline into xenia-build
|
||||
REM ============================================================================
|
||||
SET _RESULT=-2
|
||||
REM Ensure a command has been passed.
|
||||
IF -%1-==-- GOTO :show_help
|
||||
REM Dispatch to handler (:perform_foo).
|
||||
2>NUL CALL :perform_%1 %*
|
||||
IF %_RESULT% EQU -2 GOTO :show_help
|
||||
IF %_RESULT% EQU -1 GOTO :exit_nop
|
||||
IF %_RESULT% EQU 0 GOTO :exit_success
|
||||
GOTO :exit_error
|
||||
|
||||
:exit_success
|
||||
ECHO.
|
||||
ECHO OK
|
||||
EXIT /b 0
|
||||
|
||||
:exit_error
|
||||
ECHO.
|
||||
ECHO Error: %_RESULT%
|
||||
EXIT /b 1
|
||||
|
||||
:exit_nop
|
||||
ECHO.
|
||||
ECHO (no actions performed)
|
||||
EXIT /b 0
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb help
|
||||
REM ============================================================================
|
||||
:show_help
|
||||
SETLOCAL
|
||||
ECHO.
|
||||
ECHO Usage: xb COMMAND [options]
|
||||
ECHO.
|
||||
ECHO Commands:
|
||||
ECHO.
|
||||
ECHO xb setup
|
||||
ECHO Initializes dependencies and prepares build environment.
|
||||
ECHO.
|
||||
ECHO xb pull [--rebase]
|
||||
ECHO Fetches latest changes from github and rebuilds dependencies.
|
||||
ECHO.
|
||||
ECHO xb premake
|
||||
ECHO Regenerates Visual Studio projects and makefiles.
|
||||
ECHO.
|
||||
ECHO xb proto
|
||||
ECHO Regenerates protocol files (*.fbs).
|
||||
ECHO.
|
||||
ECHO xb edit
|
||||
ECHO Opens Visual Studio with `xenia.sln`.
|
||||
ECHO.
|
||||
ECHO xb build [--checked OR --debug OR --release] [--force]
|
||||
ECHO Initializes dependencies and prepares build environment.
|
||||
ECHO.
|
||||
ECHO xb gentests
|
||||
ECHO Generates test binaries (under src/xenia/cpu/frontend/testing/bin/).
|
||||
ECHO Run after modifying test .s files.
|
||||
ECHO.
|
||||
ECHO xb test [--checked OR --debug OR --release] [--continue]
|
||||
ECHO Runs automated tests. Tests must have been built with `xb build`.
|
||||
ECHO.
|
||||
ECHO xb clean
|
||||
ECHO Cleans normal build artifacts to force a rebuild.
|
||||
ECHO.
|
||||
ECHO xb nuke
|
||||
ECHO Resets branch and build environment to defaults to unhose state.
|
||||
ECHO.
|
||||
ECHO xb lint [--all] [--origin]
|
||||
ECHO Runs linter on local changes (or entire codebase).
|
||||
ECHO.
|
||||
ECHO xb format [--all] [--origin]
|
||||
ECHO Runs linter/auto-formatter on local changes (or entire codebase).
|
||||
ECHO.
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb setup
|
||||
REM ============================================================================
|
||||
:perform_setup
|
||||
SETLOCAL
|
||||
ECHO Setting up the build environment...
|
||||
|
||||
ECHO.
|
||||
ECHO ^> git submodule update --init --recursive
|
||||
git submodule update --init --recursive
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to initialize git submodules
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ECHO.
|
||||
ECHO ^> build_tools/premake ...
|
||||
CALL :run_premake
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to run premake
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb pull
|
||||
REM ============================================================================
|
||||
:perform_pull
|
||||
SETLOCAL
|
||||
SET REBASE=0
|
||||
SHIFT
|
||||
:perform_pull_args
|
||||
IF "%~1"=="" GOTO :perform_pull_parsed
|
||||
IF "%~1"=="--" GOTO :perform_pull_parsed
|
||||
IF "%~1"=="--rebase" (SET REBASE=1)
|
||||
SHIFT
|
||||
GOTO :perform_pull_args
|
||||
:perform_pull_parsed
|
||||
ECHO Pulling latest changes and rebuilding dependencies...
|
||||
|
||||
ECHO.
|
||||
ECHO ^> git checkout master
|
||||
git checkout master
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to checkout master
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ECHO.
|
||||
IF %REBASE% EQU 1 (
|
||||
ECHO ^> git pull --rebase
|
||||
git pull --rebase
|
||||
) ELSE (
|
||||
ECHO ^> git pull
|
||||
git pull
|
||||
)
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to pull latest changes from git
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ECHO.
|
||||
ECHO ^> git submodule update --recursive
|
||||
git submodule update --recursive
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to update git submodules
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ECHO.
|
||||
ECHO ^> build_tools/premake ...
|
||||
CALL :run_premake
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to run premake
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb premake
|
||||
REM ============================================================================
|
||||
:perform_premake
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
ECHO Generating project files...
|
||||
|
||||
ECHO.
|
||||
ECHO ^> build_tools/premake ...
|
||||
CALL :run_premake
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to run premake
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb proto
|
||||
REM ============================================================================
|
||||
:perform_proto
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
ECHO Generating proto files...
|
||||
|
||||
SET FLATC=build\bin\Windows\Debug\flatc.exe
|
||||
IF NOT EXIST %FLATC% (
|
||||
SET FLATC=build\bin\Windows\Release\flatc.exe
|
||||
IF NOT EXIST %FLATC% (
|
||||
ECHO.
|
||||
ECHO ERROR: flatc not built - build before running this
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
)
|
||||
|
||||
SET FBS_SRCS=src\xenia\debug\proto\
|
||||
SET CC_OUT=src\xenia\debug\proto\
|
||||
SET CS_OUT=src\Xenia.Debug\Proto\
|
||||
|
||||
SET ANY_ERRORS=0
|
||||
PUSHD %FBS_SRCS%
|
||||
FOR %%G in (*.fbs) DO (
|
||||
ECHO ^> generating %%~nG...
|
||||
POPD
|
||||
SET SRC_FILE=%FBS_SRCS%\%%G
|
||||
CMD /c build\bin\Windows\Debug\flatc.exe -c -o %CC_OUT% !SRC_FILE! 2>&1
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
CMD /c build\bin\Windows\Debug\flatc.exe -n -o %CS_OUT% !SRC_FILE! 2>&1
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
PUSHD %TEST_SRC%
|
||||
)
|
||||
POPD
|
||||
IF %ANY_ERRORS% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to build one or more tests
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb edit
|
||||
REM ============================================================================
|
||||
:perform_edit
|
||||
SETLOCAL
|
||||
ECHO Launching Visual Studio...
|
||||
|
||||
ECHO.
|
||||
ECHO ^> build_tools/premake ...
|
||||
CALL :run_premake
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to run premake
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ECHO.
|
||||
ECHO ^> devenv %XENIA_SLN%
|
||||
START devenv %XENIA_SLN%
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb build
|
||||
REM ============================================================================
|
||||
:perform_build
|
||||
SETLOCAL
|
||||
SET CONFIG="debug"
|
||||
SET FORCE=0
|
||||
SHIFT
|
||||
:perform_build_args
|
||||
IF "%~1"=="" GOTO :perform_build_parsed
|
||||
IF "%~1"=="--" GOTO :perform_build_parsed
|
||||
IF "%~1"=="--checked" (SET CONFIG="checked")
|
||||
IF "%~1"=="--debug" (SET CONFIG="debug")
|
||||
IF "%~1"=="--release" (SET CONFIG="release")
|
||||
IF "%~1"=="--force" (SET FORCE=1)
|
||||
SHIFT
|
||||
GOTO :perform_build_args
|
||||
:perform_build_parsed
|
||||
ECHO Building for config %CONFIG%...
|
||||
|
||||
ECHO.
|
||||
ECHO ^> build_tools/premake ...
|
||||
CALL :run_premake
|
||||
IF %_RESULT% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to run premake
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
IF %FORCE% EQU 1 (
|
||||
SET DEVENV_COMMAND=/rebuild
|
||||
) ELSE (
|
||||
SET DEVENV_COMMAND=/build
|
||||
)
|
||||
ECHO.
|
||||
ECHO ^> devenv %XENIA_SLN% %DEVENV_COMMAND% %CONFIG%
|
||||
|
||||
1>NUL 2>NUL CMD /c where devenv
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO devenv not found
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
CMD /C devenv %XENIA_SLN% /nologo %DEVENV_COMMAND% %CONFIG%
|
||||
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: build failed with errors
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb gentests
|
||||
REM ============================================================================
|
||||
:perform_gentests
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
ECHO Generating test binaries...
|
||||
|
||||
SET BINUTILS=third_party\binutils-ppc-cygwin
|
||||
SET PPC_AS=%BINUTILS%\powerpc-none-elf-as.exe
|
||||
SET PPC_LD=%BINUTILS%\powerpc-none-elf-ld.exe
|
||||
SET PPC_OBJDUMP=%BINUTILS%\powerpc-none-elf-objdump.exe
|
||||
SET PPC_NM=%BINUTILS%\powerpc-none-elf-nm.exe
|
||||
|
||||
SET TEST_SRC=src/xenia/cpu/frontend/testing
|
||||
SET TEST_SRC_WIN=src\xenia\cpu\frontend\testing
|
||||
SET TEST_BIN=%TEST_SRC%/bin
|
||||
SET TEST_BIN_WIN=%TEST_SRC_WIN%\bin
|
||||
IF NOT EXIST %TEST_BIN_WIN% (mkdir %TEST_BIN_WIN%)
|
||||
|
||||
SET ANY_ERRORS=0
|
||||
PUSHD %TEST_SRC_WIN%
|
||||
FOR %%G in (*.s) DO (
|
||||
ECHO ^> generating %%~nG...
|
||||
POPD
|
||||
SET SRC_FILE=%TEST_SRC%/%%G
|
||||
SET SRC_NAME=%%~nG
|
||||
SET OBJ_FILE=%TEST_BIN%/!SRC_NAME!.o
|
||||
CMD /c %PPC_AS% -a32 -be -mregnames -mpower7 -maltivec -mvsx -mvmx128 -R -o !OBJ_FILE! !SRC_FILE! 2>&1
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
%PPC_OBJDUMP% --adjust-vma=0x100000 -Mpower7 -Mvmx128 -D -EB !OBJ_FILE! > %TEST_BIN%/!SRC_NAME!.dis.tmp
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
REM Eat the first 4 lines to kill the file path that'll differ across machines.
|
||||
MORE +4 %TEST_BIN_WIN%\!SRC_NAME!.dis.tmp > %TEST_BIN_WIN%\!SRC_NAME!.dis
|
||||
DEL %TEST_BIN_WIN%\!SRC_NAME!.dis.tmp
|
||||
CMD /c %PPC_LD% -A powerpc:common32 -melf32ppc -EB -nostdlib --oformat binary -Ttext 0x80000000 -e 0x80000000 -o %TEST_BIN%/!SRC_NAME!.bin !OBJ_FILE! 2>&1
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
%PPC_NM% --numeric-sort !OBJ_FILE! > %TEST_BIN%/!SRC_NAME!.map
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
PUSHD %TEST_SRC_WIN%
|
||||
)
|
||||
POPD
|
||||
IF %ANY_ERRORS% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to build one or more tests
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb test
|
||||
REM ============================================================================
|
||||
:perform_test
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
SET BUILD=1
|
||||
SET CONFIG="debug"
|
||||
SET CONTINUE=0
|
||||
SHIFT
|
||||
:perform_test_args
|
||||
IF "%~1"=="" GOTO :perform_test_parsed
|
||||
IF "%~1"=="--" (
|
||||
SHIFT
|
||||
GOTO :perform_test_parsed
|
||||
)
|
||||
IF "%~1"=="--checked" (SET CONFIG="checked")
|
||||
IF "%~1"=="--debug" (SET CONFIG="debug")
|
||||
IF "%~1"=="--release" (SET CONFIG="release")
|
||||
IF "%~1"=="--continue" (SET CONTINUE=1)
|
||||
SHIFT
|
||||
GOTO :perform_test_args
|
||||
:perform_test_parsed
|
||||
ECHO Running automated testing for config %CONFIG%...
|
||||
|
||||
SET TEST_NAMES=xenia-cpu-frontend-tests
|
||||
FOR %%G IN (%TEST_NAMES%) DO (
|
||||
IF NOT EXIST build\bin\Windows\%CONFIG%\%%G.exe (
|
||||
ECHO.
|
||||
ECHO ERROR: unable to find `%%G.exe` - ensure it is built.
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
)
|
||||
|
||||
SET ANY_FAILED=0
|
||||
FOR %%G IN (%TEST_NAMES%) DO (
|
||||
ECHO.
|
||||
ECHO ^> build\bin\Windows\%CONFIG%\%%G.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
build\bin\Windows\%CONFIG%\%%G.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_FAILED=1
|
||||
IF %CONTINUE% EQU 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: test failed, aborting, use --continue to keep going
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
) ELSE (
|
||||
ECHO.
|
||||
ECHO ERROR: test failed but continuing due to --continue
|
||||
)
|
||||
)
|
||||
)
|
||||
IF %ANY_FAILED% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: one or more tests failed
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb clean
|
||||
REM ============================================================================
|
||||
:perform_clean
|
||||
SETLOCAL
|
||||
ECHO Cleaning normal build outputs...
|
||||
ECHO (use nuke to kill all artifacts)
|
||||
|
||||
1>NUL 2>NUL CMD /c where devenv
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO devenv not found
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
SET CONFIG_NAMES=Checked Debug Release
|
||||
FOR %%G IN (%CONFIG_NAMES%) DO (
|
||||
ECHO.
|
||||
ECHO ^> devenv %XENIA_SLN% /clean %%G
|
||||
CMD /C devenv %XENIA_SLN% /nologo /clean %%G
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb nuke
|
||||
REM ============================================================================
|
||||
:perform_nuke
|
||||
SETLOCAL
|
||||
ECHO Nuking all local changes...
|
||||
ECHO.
|
||||
|
||||
ECHO.
|
||||
ECHO ^> rmdir /s build
|
||||
rmdir /s build
|
||||
|
||||
ECHO.
|
||||
ECHO ^> git checkout --hard master
|
||||
git checkout --hard master
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb lint
|
||||
REM ============================================================================
|
||||
:perform_lint
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
SET ALL=0
|
||||
SET HEAD=HEAD
|
||||
SHIFT
|
||||
:perform_lint_args
|
||||
IF "%~1"=="" GOTO :perform_lint_parsed
|
||||
IF "%~1"=="--" GOTO :perform_lint_parsed
|
||||
IF "%~1"=="--all" (SET ALL=1)
|
||||
IF "%~1"=="--origin" (SET HEAD=origin/master)
|
||||
SHIFT
|
||||
GOTO :perform_lint_args
|
||||
:perform_lint_parsed
|
||||
IF %ALL% EQU 1 (
|
||||
ECHO Running code linter on all code...
|
||||
) ELSE (
|
||||
ECHO Running code linter on code staged in git index...
|
||||
)
|
||||
|
||||
IF %CLANG_FORMAT%=="" (
|
||||
ECHO.
|
||||
ECHO ERROR: clang-format is not on PATH or the standard location.
|
||||
ECHO LLVM is available from http://llvm.org/releases/download.html
|
||||
ECHO See docs/style_guide.md for instructions on how to get it.
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
SET ANY_ERRORS=0
|
||||
IF %ALL% NEQ 1 (
|
||||
ECHO.
|
||||
ECHO ^> git-clang-format
|
||||
CMD /c python third_party/clang-format/git-clang-format --binary=%CLANG_FORMAT% --commit=%HEAD% --diff >.difftemp.txt
|
||||
FIND /C "did not modify any files" .difftemp.txt >nul
|
||||
IF !ERRORLEVEL! EQU 1 (
|
||||
SET ANY_ERRORS=1
|
||||
CMD /c python third_party/clang-format/git-clang-format --binary=%CLANG_FORMAT% --commit=%HEAD% --diff
|
||||
)
|
||||
DEL .difftemp.txt
|
||||
) ELSE (
|
||||
PUSHD src
|
||||
FOR /R %%G in (*.cc *.c *.h *.inl) DO (
|
||||
%CLANG_FORMAT% -output-replacements-xml -style=file %%G >.difftemp.txt
|
||||
FIND /C "<replacement " .difftemp.txt >nul
|
||||
IF !ERRORLEVEL! EQU 0 (
|
||||
SET ANY_ERRORS=1
|
||||
ECHO ^> clang-format %%G
|
||||
DEL .difftemp.txt
|
||||
%CLANG_FORMAT% -style=file %%G > .difftemp.txt
|
||||
python ..\tools\diff.py "%%G" .difftemp.txt .difftemp.txt
|
||||
TYPE .difftemp.txt
|
||||
DEL .difftemp.txt
|
||||
)
|
||||
DEL .difftemp.txt
|
||||
)
|
||||
POPD
|
||||
)
|
||||
IF %ANY_ERRORS% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: 1+ diffs. Stage changes and run 'xb format' to fix.
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
REM xb format
|
||||
REM ============================================================================
|
||||
:perform_format
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
SET ALL=0
|
||||
SET HEAD=HEAD
|
||||
SHIFT
|
||||
:perform_format_args
|
||||
IF "%~1"=="" GOTO :perform_format_parsed
|
||||
IF "%~1"=="--" GOTO :perform_format_parsed
|
||||
IF "%~1"=="--all" (SET ALL=1)
|
||||
IF "%~1"=="--origin" (SET HEAD=origin/master)
|
||||
SHIFT
|
||||
GOTO :perform_format_args
|
||||
:perform_format_parsed
|
||||
IF %ALL% EQU 1 (
|
||||
ECHO Running code formatter on all code...
|
||||
) ELSE (
|
||||
ECHO Running code formatter on code staged in git index...
|
||||
)
|
||||
|
||||
IF %CLANG_FORMAT%=="" (
|
||||
ECHO.
|
||||
ECHO ERROR: clang-format is not on PATH or the standard location.
|
||||
ECHO LLVM is available from http://llvm.org/releases/download.html
|
||||
ECHO See docs/style_guide.md for instructions on how to get it.
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
SET ANY_ERRORS=0
|
||||
IF %ALL% NEQ 1 (
|
||||
ECHO.
|
||||
ECHO ^> git-clang-format
|
||||
CMD /c python third_party/clang-format/git-clang-format --binary=%CLANG_FORMAT% --commit=%HEAD%
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
) ELSE (
|
||||
PUSHD src
|
||||
FOR /R %%G in (*.cc *.c *.h *.inl) DO (
|
||||
ECHO ^> clang-format %%G
|
||||
CMD /C %CLANG_FORMAT% -i -style=file %%G
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
)
|
||||
POPD
|
||||
PUSHD third_party\elemental-forms\src
|
||||
FOR /R %%G in (*.cc *.c *.h *.inl) DO (
|
||||
ECHO ^> clang-format %%G
|
||||
CMD /C %CLANG_FORMAT% -i -style=file %%G
|
||||
IF !ERRORLEVEL! NEQ 0 (
|
||||
SET ANY_ERRORS=1
|
||||
)
|
||||
)
|
||||
POPD
|
||||
)
|
||||
IF %ANY_ERRORS% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: 1+ clang-format calls failed - ensure all files are staged
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
python xenia-build %*
|
||||
EXIT /b %ERRORLEVEL%
|
||||
|
||||
|
||||
REM ============================================================================
|
||||
|
@ -714,62 +42,3 @@ IF %ERRORLEVEL% NEQ 0 (
|
|||
)
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
:check_git
|
||||
1>NUL 2>NUL CMD /c where git
|
||||
SET _RESULT=%ERRORLEVEL%
|
||||
GOTO :eof
|
||||
|
||||
:check_msvc
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
1>NUL 2>NUL CMD /c where devenv
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
IF EXIST %VS15_VCVARSALL% (
|
||||
REM VS2015
|
||||
ECHO Sourcing Visual Studio settings from %VS15_VCVARSALL%...
|
||||
CALL %VS15_VCVARSALL% amd64
|
||||
) ELSE (
|
||||
IF EXIST %VS14_VCVARSALL% (
|
||||
REM VS2015 CTP/RC
|
||||
ECHO Sourcing Visual Studio settings from %VS14_VCVARSALL%...
|
||||
CALL %VS14_VCVARSALL% amd64
|
||||
)
|
||||
)
|
||||
)
|
||||
1>NUL 2>NUL CMD /c where devenv
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
REM Still no devenv!
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
SET HAVE_TOOLS=0
|
||||
IF "%VS140COMNTOOLS%" NEQ "" (
|
||||
IF EXIST "%VS140COMNTOOLS%" (
|
||||
REM VS2015 CTP/RC
|
||||
SET HAVE_TOOLS=1
|
||||
)
|
||||
)
|
||||
IF "%VS150COMNTOOLS%" NEQ "" (
|
||||
IF EXIST "%VS150COMNTOOLS%" (
|
||||
REM VS2015
|
||||
SET HAVE_TOOLS=1
|
||||
)
|
||||
)
|
||||
IF %HAVE_TOOLS% NEQ 1 (
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
||||
:run_premake
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
CALL build_tools\premake.bat --file=premake5.lua --os=windows --test-suite-mode=combined --verbose vs2015
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ERROR: failed to run premake
|
||||
ENDLOCAL & SET _RESULT=1
|
||||
GOTO :eof
|
||||
)
|
||||
ENDLOCAL & SET _RESULT=0
|
||||
GOTO :eof
|
||||
|
|
|
@ -0,0 +1,905 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2015 Ben Vanik. All Rights Reserved.
|
||||
|
||||
"""Main build script and tooling for xenia.
|
||||
|
||||
Run with --help or no arguments for possible commands.
|
||||
"""
|
||||
|
||||
__author__ = 'ben.vanik@gmail.com (Ben Vanik)'
|
||||
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
self_path = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def main():
|
||||
# Add self to the root search path.
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
|
||||
|
||||
# Augment path to include our fancy things.
|
||||
os.environ['PATH'] += os.pathsep + os.pathsep.join([
|
||||
self_path,
|
||||
os.path.abspath('build_tools/'),
|
||||
])
|
||||
|
||||
# Check git exists.
|
||||
if not has_bin('git'):
|
||||
print('ERROR: git must be installed and on PATH.')
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
# Check python version.
|
||||
if not sys.version_info[:2] == (2, 7):
|
||||
# TODO(benvanik): allow things to work with 3, but warn on clang-format.
|
||||
print('ERROR: Python 2.7 must be installed and on PATH')
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
# Grab Visual Studio version and execute shell to set up environment.
|
||||
if sys.platform == 'win32':
|
||||
vs_version = import_vs_environment()
|
||||
if vs_version != 2015:
|
||||
print('ERROR: Visual Studio 2015 not found!')
|
||||
print('Ensure you have the VS140COMNTOOLS environment variable!')
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
# Setup main argument parser and common arguments.
|
||||
parser = argparse.ArgumentParser(prog='xenia-build')
|
||||
|
||||
# Grab all commands and populate the argument parser for each.
|
||||
subparsers = parser.add_subparsers(title='subcommands',
|
||||
dest='subcommand')
|
||||
commands = discover_commands(subparsers)
|
||||
|
||||
# If the user passed no args, die nicely.
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
return
|
||||
|
||||
# Gather any arguments that we want to pass to child processes.
|
||||
command_args = sys.argv[1:]
|
||||
pass_args = []
|
||||
try:
|
||||
pass_index = command_args.index('--')
|
||||
pass_args = command_args[pass_index + 1:]
|
||||
command_args = command_args[:pass_index]
|
||||
except:
|
||||
pass
|
||||
|
||||
# Parse command name and dispatch.
|
||||
args = vars(parser.parse_args(command_args))
|
||||
command_name = args['subcommand']
|
||||
try:
|
||||
command = commands[command_name]
|
||||
return_code = command.execute(args, pass_args, os.getcwd())
|
||||
except Exception as e:
|
||||
raise
|
||||
return_code = 1
|
||||
sys.exit(return_code)
|
||||
|
||||
|
||||
# TODO(benvanik): move to build_tools utils module.
|
||||
def import_vs_environment():
|
||||
"""Finds the installed Visual Studio version and imports
|
||||
interesting environment variables into os.environ.
|
||||
|
||||
Returns:
|
||||
A version such as 2015 or None if no VS is found.
|
||||
"""
|
||||
version = 0
|
||||
tools_path = ''
|
||||
if 'VS140COMNTOOLS' in os.environ:
|
||||
version = 2015
|
||||
tools_path = os.environ['VS140COMNTOOLS']
|
||||
if version == 0:
|
||||
return None
|
||||
tools_path = os.path.join(tools_path, '..\\..\\vc\\vcvarsall.bat')
|
||||
|
||||
args = [tools_path, '&&', 'set']
|
||||
popen = subprocess.Popen(
|
||||
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
variables, _ = popen.communicate()
|
||||
envvars_to_save = (
|
||||
'devenvdir',
|
||||
'include',
|
||||
'lib',
|
||||
'libpath',
|
||||
'path',
|
||||
'pathext',
|
||||
'systemroot',
|
||||
'temp',
|
||||
'tmp',
|
||||
'windowssdkdir',
|
||||
)
|
||||
for line in variables.splitlines():
|
||||
for envvar in envvars_to_save:
|
||||
if re.match(envvar + '=', line.lower()):
|
||||
var, setting = line.split('=', 1)
|
||||
if envvar == 'path':
|
||||
setting = os.path.dirname(sys.executable) + os.pathsep + setting
|
||||
os.environ[var.upper()] = setting
|
||||
break
|
||||
|
||||
os.environ['VSVERSION'] = str(version)
|
||||
return version
|
||||
|
||||
|
||||
def has_bin(bin):
|
||||
"""Checks whether the given binary is present.
|
||||
"""
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
path = path.strip('"')
|
||||
exe_file = os.path.join(path, bin)
|
||||
if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK):
|
||||
return True
|
||||
exe_file = exe_file + '.exe'
|
||||
if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK):
|
||||
return True
|
||||
return None
|
||||
|
||||
|
||||
def shell_call(command, throw_on_error=True, stdout_path=None):
|
||||
"""Executes a shell command.
|
||||
|
||||
Args:
|
||||
command: Command to execute, as a list of parameters.
|
||||
throw_on_error: Whether to throw an error or return the status code.
|
||||
stdout_path: File path to write stdout output to.
|
||||
|
||||
Returns:
|
||||
If throw_on_error is False the status code of the call will be returned.
|
||||
"""
|
||||
stdout_file = None
|
||||
if stdout_path:
|
||||
stdout_file = open(stdout_path, 'w')
|
||||
result = 0
|
||||
try:
|
||||
if throw_on_error:
|
||||
result = 1
|
||||
subprocess.check_call(command, shell=True, stdout=stdout_file)
|
||||
result = 0
|
||||
else:
|
||||
result = subprocess.call(command, shell=True, stdout=stdout_file)
|
||||
finally:
|
||||
if stdout_file:
|
||||
stdout_file.close()
|
||||
return result
|
||||
|
||||
|
||||
def run_premake(target_os, action):
|
||||
"""Runs premake on the main project with the given format.
|
||||
|
||||
Args:
|
||||
target_os: target --os to pass to premake.
|
||||
action: action to preform.
|
||||
"""
|
||||
shell_call([
|
||||
'python',
|
||||
os.path.join('build_tools', 'premake'),
|
||||
'--file=premake5.lua',
|
||||
'--os=%s' % (target_os),
|
||||
'--cc=clang',
|
||||
'--test-suite-mode=combined',
|
||||
'--verbose',
|
||||
action,
|
||||
])
|
||||
|
||||
|
||||
def run_premake_clean():
|
||||
"""Runs a premake clean operation.
|
||||
"""
|
||||
if sys.platform == 'darwin':
|
||||
run_premake('macosx', 'clean')
|
||||
elif sys.platform == 'win32':
|
||||
run_premake('windows', 'clean')
|
||||
else:
|
||||
run_premake('linux', 'clean')
|
||||
|
||||
|
||||
def run_platform_premake():
|
||||
"""Runs all gyp configurations.
|
||||
"""
|
||||
if sys.platform == 'darwin':
|
||||
run_premake('macosx', 'xcode')
|
||||
elif sys.platform == 'win32':
|
||||
run_premake('windows', 'vs2015')
|
||||
else:
|
||||
run_premake('linux', 'gmake')
|
||||
|
||||
|
||||
def get_build_bin_path(args):
|
||||
"""Returns the path of the bin/ path with build results based on the
|
||||
configuration specified in the parsed arguments.
|
||||
|
||||
Args:
|
||||
args: Parsed arguments.
|
||||
|
||||
Returns:
|
||||
A full path for the bin folder.
|
||||
"""
|
||||
if sys.platform == 'darwin':
|
||||
platform = 'macosx'
|
||||
elif sys.platform == 'win32':
|
||||
platform = 'windows'
|
||||
else:
|
||||
platform = 'linux'
|
||||
return os.path.join(self_path, 'build', 'bin', platform, args['config'])
|
||||
|
||||
|
||||
def discover_commands(subparsers):
|
||||
"""Looks for all commands and returns a dictionary of them.
|
||||
In the future commands could be discovered on disk.
|
||||
|
||||
Args:
|
||||
subparsers: Argument subparsers parent used to add command parsers.
|
||||
|
||||
Returns:
|
||||
A dictionary containing name-to-Command mappings.
|
||||
"""
|
||||
commands = {
|
||||
'setup': SetupCommand(subparsers),
|
||||
'pull': PullCommand(subparsers),
|
||||
'premake': PremakeCommand(subparsers),
|
||||
'build': BuildCommand(subparsers),
|
||||
'gentests': GenTestsCommand(subparsers),
|
||||
'test': TestCommand(subparsers),
|
||||
'clean': CleanCommand(subparsers),
|
||||
'nuke': NukeCommand(subparsers),
|
||||
'lint': LintCommand(subparsers),
|
||||
'format': FormatCommand(subparsers),
|
||||
}
|
||||
if sys.platform == 'win32':
|
||||
commands['devenv'] = DevenvCommand(subparsers)
|
||||
return commands
|
||||
|
||||
|
||||
class Command(object):
|
||||
"""Base type for commands.
|
||||
"""
|
||||
|
||||
def __init__(self, subparsers, name, help_short=None, help_long=None,
|
||||
*args, **kwargs):
|
||||
"""Initializes a command.
|
||||
|
||||
Args:
|
||||
subparsers: Argument subparsers parent used to add command parsers.
|
||||
name: The name of the command exposed to the management script.
|
||||
help_short: Help text printed alongside the command when queried.
|
||||
help_long: Extended help text when viewing command help.
|
||||
"""
|
||||
self.name = name
|
||||
self.help_short = help_short
|
||||
self.help_long = help_long
|
||||
|
||||
self.parser = subparsers.add_parser(name,
|
||||
help=help_short,
|
||||
description=help_long)
|
||||
self.parser.set_defaults(command_handler=self)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
"""Executes the command.
|
||||
|
||||
Args:
|
||||
args: Arguments hash for the command.
|
||||
pass_args: Arguments list to pass to child commands.
|
||||
cwd: Current working directory.
|
||||
|
||||
Returns:
|
||||
Return code of the command.
|
||||
"""
|
||||
return 1
|
||||
|
||||
|
||||
class SetupCommand(Command):
|
||||
"""'setup' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(SetupCommand, self).__init__(
|
||||
subparsers,
|
||||
name='setup',
|
||||
help_short='Setup the build environment.',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Setting up the build environment...')
|
||||
print('')
|
||||
|
||||
# Setup submodules.
|
||||
print('- git submodule init / update...')
|
||||
shell_call([
|
||||
'git',
|
||||
'submodule',
|
||||
'update',
|
||||
'--init',
|
||||
'--recursive',
|
||||
])
|
||||
print('')
|
||||
|
||||
print('- running premake...')
|
||||
run_platform_premake()
|
||||
print('')
|
||||
|
||||
print('Success!')
|
||||
return 0
|
||||
|
||||
|
||||
class PullCommand(Command):
|
||||
"""'pull' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(PullCommand, self).__init__(
|
||||
subparsers,
|
||||
name='pull',
|
||||
help_short='Pulls the repo and all dependencies and rebases changes.',
|
||||
*args, **kwargs)
|
||||
self.parser.add_argument('--merge', action='store_true',
|
||||
help='Merges on master instead of rebasing.')
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Pulling...')
|
||||
print('')
|
||||
|
||||
print('- switching to master...')
|
||||
shell_call([
|
||||
'git',
|
||||
'checkout',
|
||||
'master',
|
||||
])
|
||||
print('')
|
||||
|
||||
print('- pulling self...')
|
||||
if args['merge']:
|
||||
shell_call([
|
||||
'git',
|
||||
'pull',
|
||||
])
|
||||
else:
|
||||
shell_call([
|
||||
'git',
|
||||
'pull',
|
||||
'--rebase',
|
||||
])
|
||||
print('')
|
||||
|
||||
print('- pulling dependencies...')
|
||||
shell_call([
|
||||
'git',
|
||||
'submodule',
|
||||
'update',
|
||||
'--init',
|
||||
'--recursive',
|
||||
])
|
||||
print('')
|
||||
|
||||
print('- running premake...')
|
||||
run_platform_premake()
|
||||
print('')
|
||||
|
||||
print('Success!')
|
||||
return 0
|
||||
|
||||
|
||||
class PremakeCommand(Command):
|
||||
"""'premake' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(PremakeCommand, self).__init__(
|
||||
subparsers,
|
||||
name='premake',
|
||||
help_short='Runs premake to update all projects.',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Running premake...')
|
||||
print('')
|
||||
|
||||
# Update premake.
|
||||
run_platform_premake()
|
||||
|
||||
print('Success!')
|
||||
return 0
|
||||
|
||||
|
||||
class BaseBuildCommand(Command):
|
||||
"""Base command for things that require building."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(BaseBuildCommand, self).__init__(
|
||||
subparsers,
|
||||
*args, **kwargs)
|
||||
self.parser.add_argument(
|
||||
'--config', choices=['checked', 'debug', 'release'], default='debug',
|
||||
help='Chooses the build configuration.')
|
||||
self.parser.add_argument(
|
||||
'--target', action='append', default=[],
|
||||
help='Builds only the given target(s).')
|
||||
self.parser.add_argument(
|
||||
'--force', action='store_true',
|
||||
help='Forces a full rebuild.')
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('- running premake...')
|
||||
run_platform_premake()
|
||||
print('')
|
||||
|
||||
print('- building (%s):%s...' % (
|
||||
'all' if not len(args['target']) else ' '.join(args['target']),
|
||||
args['config']))
|
||||
if sys.platform == 'win32':
|
||||
result = shell_call([
|
||||
'devenv',
|
||||
'/nologo',
|
||||
'build/xenia.sln',
|
||||
'/rebuild' if args['force'] else '/build',
|
||||
args['config'],
|
||||
] + [('/project ', target) for target in args['target']] +
|
||||
pass_args, throw_on_error=False)
|
||||
else:
|
||||
# TODO(benvanik): other platforms.
|
||||
print('ERROR: don\'t know how to build on this platform.')
|
||||
print('')
|
||||
if result != 0:
|
||||
print('ERROR: build failed with one or more errors.')
|
||||
return result
|
||||
return 0
|
||||
|
||||
|
||||
class BuildCommand(BaseBuildCommand):
|
||||
"""'build' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(BuildCommand, self).__init__(
|
||||
subparsers,
|
||||
name='build',
|
||||
help_short='Builds the project.',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Building %s...' % (args['config']))
|
||||
print('')
|
||||
|
||||
result = super(BuildCommand, self).execute(args, pass_args, cwd)
|
||||
if not result:
|
||||
print('Success!')
|
||||
return result
|
||||
|
||||
|
||||
class TestCommand(BaseBuildCommand):
|
||||
"""'test' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(TestCommand, self).__init__(
|
||||
subparsers,
|
||||
name='test',
|
||||
help_short='Runs automated tests that have been built with `xb build`.',
|
||||
help_long='''
|
||||
To pass arguments to the test executables separate them with `--`.
|
||||
For example, you can run only the instr_foo.s tests with:
|
||||
$ xb test -- instr_foo
|
||||
''',
|
||||
*args, **kwargs)
|
||||
self.parser.add_argument(
|
||||
'--no-build', action='store_true',
|
||||
help='Don\'t build before running tests.')
|
||||
self.parser.add_argument(
|
||||
'--continue', action='store_true',
|
||||
help='Don\'t stop when a test errors, but continue running all.')
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Testing...')
|
||||
print('')
|
||||
|
||||
# The test executables that will be built and run.
|
||||
test_targets = args['target'] or [
|
||||
'xenia-cpu-frontend-tests',
|
||||
]
|
||||
args['target'] = test_targets
|
||||
|
||||
# Build all targets (if desired).
|
||||
if not args['no_build']:
|
||||
result = super(TestCommand, self).execute(args, [], cwd)
|
||||
if result:
|
||||
print('Failed to build, aborting test run.')
|
||||
return result
|
||||
|
||||
# Ensure all targets exist before we run.
|
||||
test_executables = [
|
||||
os.path.join(get_build_bin_path(args), test_target)
|
||||
for test_target in test_targets]
|
||||
for test_executable in test_executables:
|
||||
if not has_bin(test_executable):
|
||||
print('ERROR: Unable to find %s - build it.' % (test_executable))
|
||||
return 1
|
||||
|
||||
# Run tests.
|
||||
any_failed = False
|
||||
for test_executable in test_executables:
|
||||
print('- %s' % (test_executable))
|
||||
result = shell_call([
|
||||
test_executable,
|
||||
] + pass_args,
|
||||
throw_on_error=False)
|
||||
if result:
|
||||
any_failed = True
|
||||
if args['continue']:
|
||||
print('ERROR: test failed but continuing due to --continue.')
|
||||
else:
|
||||
print('ERROR: test failed, aborting, use --continue to keep going.')
|
||||
return result
|
||||
|
||||
if any_failed:
|
||||
print('ERROR: one or more tests failed.')
|
||||
result = 1
|
||||
return result
|
||||
|
||||
|
||||
class GenTestsCommand(Command):
|
||||
"""'gentests' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(GenTestsCommand, self).__init__(
|
||||
subparsers,
|
||||
name='gentests',
|
||||
help_short='Generates test binaries.',
|
||||
help_long='''
|
||||
Generates test binaries (under src/xenia/cpu/frontend/testing/bin/).
|
||||
Run after modifying test .s files.
|
||||
''',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Generating test binaries...')
|
||||
print('')
|
||||
|
||||
binutils_path = os.path.join('third_party', 'binutils-ppc-cygwin')
|
||||
ppc_as = os.path.join(binutils_path, 'powerpc-none-elf-as')
|
||||
ppc_ld = os.path.join(binutils_path, 'powerpc-none-elf-ld')
|
||||
ppc_objdump = os.path.join(binutils_path, 'powerpc-none-elf-objdump')
|
||||
ppc_nm = os.path.join(binutils_path, 'powerpc-none-elf-nm')
|
||||
|
||||
test_src = os.path.join('src', 'xenia', 'cpu', 'frontend', 'testing')
|
||||
test_bin = os.path.join(test_src, 'bin')
|
||||
|
||||
# Ensure the test output path exists.
|
||||
if not os.path.exists(test_bin):
|
||||
os.mkdir(test_bin)
|
||||
|
||||
src_files = [os.path.join(root, name)
|
||||
for root, dirs, files in os.walk('src')
|
||||
for name in files
|
||||
if name.endswith(('.s'))]
|
||||
|
||||
def make_unix_path(p):
|
||||
"""Forces a unix path separator style, as required by binutils.
|
||||
"""
|
||||
return string.replace(p, os.sep, '/')
|
||||
|
||||
any_errors = False
|
||||
for src_file in src_files:
|
||||
print('- %s' % (src_file))
|
||||
src_name = os.path.splitext(os.path.basename(src_file))[0]
|
||||
obj_file = os.path.join(test_bin, src_name) + '.o'
|
||||
shell_call([
|
||||
ppc_as,
|
||||
'-a32',
|
||||
'-be',
|
||||
'-mregnames',
|
||||
'-mpower7',
|
||||
'-maltivec',
|
||||
'-mvsx',
|
||||
'-mvmx128',
|
||||
'-R',
|
||||
'-o%s' % (make_unix_path(obj_file)),
|
||||
make_unix_path(src_file),
|
||||
])
|
||||
dis_file = os.path.join(test_bin, src_name) + '.dis'
|
||||
shell_call([
|
||||
ppc_objdump,
|
||||
'--adjust-vma=0x100000',
|
||||
'-Mpower7',
|
||||
'-Mvmx128',
|
||||
'-D',
|
||||
'-EB',
|
||||
make_unix_path(obj_file),
|
||||
], stdout_path=dis_file)
|
||||
# Eat the first 4 lines to kill the file path that'll differ across machines.
|
||||
with open(dis_file) as f:
|
||||
dis_file_lines = f.readlines()
|
||||
with open(dis_file, 'w') as f:
|
||||
f.writelines(dis_file_lines[4:])
|
||||
shell_call([
|
||||
ppc_ld,
|
||||
'-A powerpc:common32',
|
||||
'-melf32ppc',
|
||||
'-EB',
|
||||
'-nostdlib',
|
||||
'--oformat=binary',
|
||||
'-Ttext=0x80000000',
|
||||
'-e0x80000000',
|
||||
'-o%s' % (make_unix_path(os.path.join(test_bin, src_name) + '.bin')),
|
||||
make_unix_path(obj_file),
|
||||
])
|
||||
shell_call([
|
||||
ppc_nm,
|
||||
'--numeric-sort',
|
||||
make_unix_path(obj_file),
|
||||
], stdout_path=os.path.join(test_bin, src_name) + '.map')
|
||||
|
||||
if any_errors:
|
||||
print('ERROR: failed to build one or more tests.')
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class CleanCommand(Command):
|
||||
"""'clean' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(CleanCommand, self).__init__(
|
||||
subparsers,
|
||||
name='clean',
|
||||
help_short='Removes intermediate files and build outputs.',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Cleaning build artifacts...')
|
||||
print('')
|
||||
|
||||
print('- premake clean...')
|
||||
run_premake_clean()
|
||||
print('')
|
||||
|
||||
print('Success!')
|
||||
return 0
|
||||
|
||||
|
||||
class NukeCommand(Command):
|
||||
"""'nuke' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(NukeCommand, self).__init__(
|
||||
subparsers,
|
||||
name='nuke',
|
||||
help_short='Removes all build/ output.',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Cleaning build artifacts...')
|
||||
print('')
|
||||
|
||||
print('- removing build/...')
|
||||
if os.path.isdir('build/'):
|
||||
shutil.rmtree('build/')
|
||||
print('')
|
||||
|
||||
print('- git reset to master...')
|
||||
shell_call([
|
||||
'git',
|
||||
'checkout',
|
||||
'--hard',
|
||||
'master',
|
||||
])
|
||||
print('')
|
||||
|
||||
print('- running premake...')
|
||||
run_platform_premake()
|
||||
print('')
|
||||
|
||||
print('Success!')
|
||||
return 0
|
||||
|
||||
|
||||
class LintCommand(Command):
|
||||
"""'lint' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(LintCommand, self).__init__(
|
||||
subparsers,
|
||||
name='lint',
|
||||
help_short='Checks for lint errors with clang-format.',
|
||||
*args, **kwargs)
|
||||
self.parser.add_argument(
|
||||
'--all', action='store_true',
|
||||
help='Lint all files, not just those changed.')
|
||||
self.parser.add_argument(
|
||||
'--origin', action='store_true',
|
||||
help='Lints all files changed relative to origin/master.')
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
clang_format_binary = 'clang-format'
|
||||
win32_binary = 'C:\\Program Files (x86)\\LLVM\\bin\\clang-format.exe'
|
||||
if os.path.exists(win32_binary):
|
||||
clang_format_binary = win32_binary
|
||||
if not has_bin(clang_format_binary):
|
||||
print 'ERROR: clang-format is not on PATH'
|
||||
print 'LLVM is available from http://llvm.org/releases/download.html'
|
||||
print 'See docs/style_guide.md for instructions on how to get it'
|
||||
return 1
|
||||
|
||||
difftemp = '.difftemp.txt'
|
||||
|
||||
if args['all']:
|
||||
all_files = [os.path.join(root, name)
|
||||
for root, dirs, files in os.walk('src')
|
||||
for name in files
|
||||
if name.endswith(('.cc', '.c', '.h', '.inl'))]
|
||||
print('- linting %d files' % (len(all_files)))
|
||||
any_errors = False
|
||||
for file_path in all_files:
|
||||
if os.path.exists(difftemp): os.remove(difftemp)
|
||||
ret = shell_call([
|
||||
clang_format_binary,
|
||||
'-output-replacements-xml',
|
||||
'-style=file',
|
||||
file_path,
|
||||
], throw_on_error=False, stdout_path=difftemp)
|
||||
with open(difftemp) as f:
|
||||
had_errors = '<replacement ' in f.read()
|
||||
if os.path.exists(difftemp): os.remove(difftemp)
|
||||
if had_errors:
|
||||
any_errors = True
|
||||
print('')
|
||||
print(file_path)
|
||||
shell_call([
|
||||
clang_format_binary,
|
||||
'-style=file',
|
||||
file_path,
|
||||
], throw_on_error=False, stdout_path=difftemp)
|
||||
shell_call([
|
||||
'python',
|
||||
'tools/diff.py',
|
||||
file_path,
|
||||
difftemp,
|
||||
difftemp,
|
||||
])
|
||||
shell_call([
|
||||
'type',
|
||||
difftemp,
|
||||
])
|
||||
if os.path.exists(difftemp): os.remove(difftemp)
|
||||
print('')
|
||||
print('')
|
||||
if any_errors:
|
||||
print('ERROR: 1+ diffs. Stage changes and run \'xb format\' to fix.')
|
||||
return 1
|
||||
else:
|
||||
print('Linting completed successfully.')
|
||||
return 0
|
||||
else:
|
||||
print('- git-clang-format --diff')
|
||||
if os.path.exists(difftemp): os.remove(difftemp)
|
||||
ret = shell_call([
|
||||
'python',
|
||||
'third_party/clang-format/git-clang-format',
|
||||
'--binary=%s' % (clang_format_binary),
|
||||
'--commit=%s' % ('origin/master' if args['origin'] else 'HEAD'),
|
||||
'--diff',
|
||||
], throw_on_error=False, stdout_path=difftemp)
|
||||
with open(difftemp) as f:
|
||||
not_modified = 'no modified files' in f.read()
|
||||
f.close()
|
||||
if os.path.exists(difftemp): os.remove(difftemp)
|
||||
if not not_modified:
|
||||
any_errors = True
|
||||
print('')
|
||||
shell_call([
|
||||
'python',
|
||||
'third_party/clang-format/git-clang-format',
|
||||
'--binary=%s' % (clang_format_binary),
|
||||
'--commit=%s' % ('origin/master' if args['origin'] else 'HEAD'),
|
||||
'--diff',
|
||||
])
|
||||
print('ERROR: 1+ diffs. Stage changes and run \'xb format\' to fix.')
|
||||
return 1
|
||||
else:
|
||||
print('Linting completed successfully.')
|
||||
return 0
|
||||
|
||||
|
||||
class FormatCommand(Command):
|
||||
"""'format' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(FormatCommand, self).__init__(
|
||||
subparsers,
|
||||
name='format',
|
||||
help_short='Reformats staged code with clang-format.',
|
||||
*args, **kwargs)
|
||||
self.parser.add_argument(
|
||||
'--all', action='store_true',
|
||||
help='Format all files, not just those changed.')
|
||||
self.parser.add_argument(
|
||||
'--origin', action='store_true',
|
||||
help='Formats all files changed relative to origin/master.')
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
clang_format_binary = 'clang-format'
|
||||
win32_binary = 'C:\\Program Files (x86)\\LLVM\\bin\\clang-format.exe'
|
||||
if os.path.exists(win32_binary):
|
||||
clang_format_binary = win32_binary
|
||||
if not has_bin(clang_format_binary):
|
||||
print 'ERROR: clang-format is not on PATH'
|
||||
print 'LLVM is available from http://llvm.org/releases/download.html'
|
||||
print 'See docs/style_guide.md for instructions on how to get it'
|
||||
return 1
|
||||
|
||||
if args['all']:
|
||||
all_files = [os.path.join(root, name)
|
||||
for root, dirs, files in os.walk('src/')
|
||||
for name in files
|
||||
if name.endswith(('.cc', '.c', '.h', '.inl'))]
|
||||
print('- clang-format [%d files]' % (len(all_files)))
|
||||
any_errors = False
|
||||
for file_path in all_files:
|
||||
ret = shell_call([
|
||||
clang_format_binary,
|
||||
'-i',
|
||||
'-style=file',
|
||||
file_path,
|
||||
], throw_on_error=False)
|
||||
if ret:
|
||||
any_errors = True
|
||||
print('')
|
||||
if any_errors:
|
||||
print('ERROR: 1+ clang-format calls failed.')
|
||||
print('Ensure all files are staged.')
|
||||
return 1
|
||||
else:
|
||||
print('Formatting completed successfully.')
|
||||
return 0
|
||||
else:
|
||||
print('- git-clang-format')
|
||||
shell_call([
|
||||
'python',
|
||||
'third_party/clang-format/git-clang-format',
|
||||
'--binary=%s' % (clang_format_binary),
|
||||
'--commit=%s' % ('origin/master' if args['origin'] else 'HEAD'),
|
||||
])
|
||||
print('')
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
class DevenvCommand(Command):
|
||||
"""'devenv' command."""
|
||||
|
||||
def __init__(self, subparsers, *args, **kwargs):
|
||||
super(DevenvCommand, self).__init__(
|
||||
subparsers,
|
||||
name='devenv',
|
||||
help_short='Launches Visual Studio with the sln.',
|
||||
*args, **kwargs)
|
||||
|
||||
def execute(self, args, pass_args, cwd):
|
||||
print('Launching Visual Studio...')
|
||||
print('')
|
||||
|
||||
print('- running premake...')
|
||||
run_platform_premake()
|
||||
print('')
|
||||
|
||||
print('- launching devenv...')
|
||||
shell_call([
|
||||
'devenv',
|
||||
'build\\xenia.sln',
|
||||
])
|
||||
print('')
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue