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:
|
# Build on command line:
|
||||||
> xb build
|
> xb build
|
||||||
# Run premake and open Visual Studio (run the 'xenia-app' project):
|
# Run premake and open Visual Studio (run the 'xenia-app' project):
|
||||||
> xb edit
|
> xb devenv
|
||||||
# Run premake to update the sln/vcproj's:
|
# Run premake to update the sln/vcproj's:
|
||||||
> xb premake
|
> xb premake
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ff0bab3c8e3579684b0a5634d97f181bca8d0543
|
Subproject commit 13552a8942c1fa5527e80698516912ad08d9e1ab
|
|
@ -46,12 +46,18 @@ void AttachConsole() {
|
||||||
setvbuf(stderr, nullptr, _IONBF, 0);
|
setvbuf(stderr, nullptr, _IONBF, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xe
|
int Main() {
|
||||||
|
|
||||||
// Used in console mode apps; automatically picked based on subsystem.
|
|
||||||
int main(int argc, wchar_t* argv[]) {
|
|
||||||
auto entry_info = xe::GetEntryInfo();
|
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: ") +
|
google::SetUsageMessage(std::string("usage: ") +
|
||||||
xe::to_string(entry_info.usage));
|
xe::to_string(entry_info.usage));
|
||||||
google::SetVersionString("1.0");
|
google::SetVersionString("1.0");
|
||||||
|
@ -82,30 +88,23 @@ int main(int argc, wchar_t* argv[]) {
|
||||||
int result = entry_info.entry_point(args);
|
int result = entry_info.entry_point(args);
|
||||||
|
|
||||||
google::ShutDownCommandLineFlags();
|
google::ShutDownCommandLineFlags();
|
||||||
|
LocalFree(argv);
|
||||||
return result;
|
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.
|
// Used in windowed apps; automatically picked based on subsystem.
|
||||||
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR command_line, int) {
|
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR command_line, int) {
|
||||||
// Attach a console so we can write output to stdout. If the user hasn't
|
// Attach a console so we can write output to stdout. If the user hasn't
|
||||||
// redirected output themselves it'll pop up a window.
|
// redirected output themselves it'll pop up a window.
|
||||||
xe::AttachConsole();
|
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.
|
// Run normal entry point.
|
||||||
int result = main(argc, argv);
|
return xe::Main();
|
||||||
|
|
||||||
LocalFree(argv);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined _M_IX86
|
#if defined _M_IX86
|
||||||
|
|
|
@ -62,22 +62,12 @@ LPSYMGETSYMFROMADDR64 sym_get_sym_from_addr_64_ = nullptr;
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
class Win32StackWalker : public StackWalker {
|
bool InitializeStackWalker() {
|
||||||
public:
|
if (sym_get_options_) {
|
||||||
Win32StackWalker(backend::CodeCache* code_cache) {
|
// Already initialized.
|
||||||
// Get the boundaries of the code cache so we can quickly tell if a symbol
|
return true;
|
||||||
// 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_);
|
|
||||||
|
|
||||||
// Attempt to load dbghelp.
|
// Attempt to load dbghelp.
|
||||||
// NOTE: we never free it. That's fine.
|
// NOTE: we never free it. That's fine.
|
||||||
HMODULE module = LoadLibrary(TEXT("dbghelp.dll"));
|
HMODULE module = LoadLibrary(TEXT("dbghelp.dll"));
|
||||||
|
@ -93,8 +83,7 @@ class Win32StackWalker : public StackWalker {
|
||||||
GetProcAddress(module, "SymInitialize"));
|
GetProcAddress(module, "SymInitialize"));
|
||||||
stack_walk_64_ =
|
stack_walk_64_ =
|
||||||
reinterpret_cast<LPSTACKWALK64>(GetProcAddress(module, "StackWalk64"));
|
reinterpret_cast<LPSTACKWALK64>(GetProcAddress(module, "StackWalk64"));
|
||||||
sym_function_table_access_64_ =
|
sym_function_table_access_64_ = reinterpret_cast<LPSYMFUNCTIONTABLEACCESS64>(
|
||||||
reinterpret_cast<LPSYMFUNCTIONTABLEACCESS64>(
|
|
||||||
GetProcAddress(module, "SymFunctionTableAccess64"));
|
GetProcAddress(module, "SymFunctionTableAccess64"));
|
||||||
sym_get_module_base_64_ = reinterpret_cast<LPSYMGETMODULEBASE64>(
|
sym_get_module_base_64_ = reinterpret_cast<LPSYMGETMODULEBASE64>(
|
||||||
GetProcAddress(module, "SymGetModuleBase64"));
|
GetProcAddress(module, "SymGetModuleBase64"));
|
||||||
|
@ -122,6 +111,24 @@ class Win32StackWalker : public StackWalker {
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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 CaptureStackTrace(uint64_t* frame_host_pcs, size_t frame_offset,
|
||||||
|
|
737
xb.bat
737
xb.bat
|
@ -3,22 +3,9 @@ REM Copyright 2015 Ben Vanik. All Rights Reserved.
|
||||||
|
|
||||||
SET DIR=%~dp0
|
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 ============================================================================
|
||||||
REM Environment Validation
|
REM Environment Validation
|
||||||
REM ============================================================================
|
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
|
CALL :check_python
|
||||||
IF %_RESULT% NEQ 0 (
|
IF %_RESULT% NEQ 0 (
|
||||||
|
@ -28,672 +15,13 @@ IF %_RESULT% NEQ 0 (
|
||||||
GOTO :exit_error
|
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 ============================================================================
|
||||||
REM Command Parsing
|
REM Trampoline into xenia-build
|
||||||
REM ============================================================================
|
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
|
python xenia-build %*
|
||||||
ECHO.
|
EXIT /b %ERRORLEVEL%
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
REM ============================================================================
|
REM ============================================================================
|
||||||
|
@ -714,62 +42,3 @@ IF %ERRORLEVEL% NEQ 0 (
|
||||||
)
|
)
|
||||||
ENDLOCAL & SET _RESULT=0
|
ENDLOCAL & SET _RESULT=0
|
||||||
GOTO :eof
|
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