diff --git a/prepare-release.sh b/prepare-release.sh index dcb4295..4d193ad 100755 --- a/prepare-release.sh +++ b/prepare-release.sh @@ -6,8 +6,7 @@ MY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" source common.sh WORK_DIR="${MY_DIR}/prep" -ARTIFACT_TARBALL="${DIST_PACKAGE_NAME_BASE}.tar.bz2" -ARTIFACTS_DIR="${WORK_DIR}/artifacts" +ARTIFACTS_DIR="${WORK_DIR}" ARTIFACT_ZIP="${1}" XA_TAG_COMPONENT="${2}" @@ -38,12 +37,6 @@ function prepare() echo Unpacking artifact ZIP unzip "${ARTIFACT_ZIP}" - if [ ! -f "${ARTIFACT_TARBALL}" ]; then - die Build artifact tarball $(pwd)/${ARTIFACT_TARBALL} not found - fi - - echo Unpacking binaries tarball - tar xf "${ARTIFACT_TARBALL}" if [ ! -d "${ARTIFACTS_DIR}" ]; then die Artifacts directory ${ARTIFACTS_DIR} does not exist fi diff --git a/src/gas/command_line.cc b/src/gas/command_line.cc index bf59ebe..9801418 100644 --- a/src/gas/command_line.cc +++ b/src/gas/command_line.cc @@ -5,7 +5,6 @@ #include #include "command_line.hh" -#include "exceptions.hh" #include "platform.hh" using namespace xamarin::android::gas; @@ -34,7 +33,8 @@ bool CommandLine::parse (std::span options, std::vector if (last_opt.has_value ()) { option_cb (last_opt.value (), option); } else { - throw invalid_argument_error { "Option '" + option + "' requires an argument." }; + STDERR << "Option '" << option << "' requires an argument."; + return false; } next_arg_is_value = false; @@ -83,7 +83,7 @@ bool CommandLine::parse (std::span options, std::vector auto match = std::find_if (options.begin (), options.end (), matching_option); #endif if (match == options.end ()) { - STDERR << "Uncrecognized option '" << option << "'\n"; + STDERR << "Unrecognized option '" << option << Constants::newline; continue; } @@ -98,11 +98,8 @@ bool CommandLine::parse (std::span options, std::vector } if (last_opt.has_value ()) { - platform::string message { "Option '" }; - message - .append (last_opt.value ().name) - .append ("' requires an argument."); - throw invalid_operation_error {message}; + STDERR << "Option '" << last_opt.value().name << "' requires an argument." << std::endl; + return false; } return true; diff --git a/src/gas/command_line.hh b/src/gas/command_line.hh index a4f57e6..23623d9 100644 --- a/src/gas/command_line.hh +++ b/src/gas/command_line.hh @@ -113,8 +113,8 @@ namespace xamarin::android::gas #define CLISTR(_str_lit_) PSTR((_str_lit_)) -#if !defined (_WIN32) -#define CLIPARAM(_str_lit_) std::string_view { _str_lit_ } +#if defined (_WIN32) +#define CLIPARAM(_str_lit_) std::wstring_view { L ## _str_lit_ } #else #define CLIPARAM(_str_lit_) std::string_view { _str_lit_ } #endif diff --git a/src/gas/gas.cc b/src/gas/gas.cc index 2b0759a..f806990 100644 --- a/src/gas/gas.cc +++ b/src/gas/gas.cc @@ -58,7 +58,7 @@ int Gas::usage (bool is_error, platform::string const message) return is_error ? 1 : 0; } -std::vector Gas::get_command_line (int &argc, char **&argv) +std::vector Gas::get_command_line (int argc, argv_char **argv) { std::vector ret; @@ -173,11 +173,11 @@ int Gas::run (std::vector args) ld_path /= ld_name; auto ld = std::make_unique (ld_path); ld->append_program_argument (PSTR("-o")); - ld->append_program_argument (_gas_output_file.empty () ? platform::string (Constants::default_output_name) : _gas_output_file.string ()); + ld->append_program_argument (_gas_output_file.empty () ? platform::string (Constants::default_output_name) : _gas_output_file.native ()); ld->append_program_argument (PSTR("--relocatable")); for (fs::path const& output : output_files) { - ld->append_program_argument (output.string ()); + ld->append_program_argument (output.native ()); } return ld->run (); diff --git a/src/gas/gas.hh b/src/gas/gas.hh index 5c6c6d4..a3b9115 100644 --- a/src/gas/gas.hh +++ b/src/gas/gas.hh @@ -108,7 +108,9 @@ namespace xamarin::android::gas ~Gas () {} - std::vector get_command_line (int &argc, char **&argv); + void dump_command_line_args (int argc, argv_char **argv); + static void platform_setup (); + std::vector get_command_line (int argc, argv_char **argv); int run (std::vector args); diff --git a/src/gas/gas.posix.cc b/src/gas/gas.posix.cc index 84b5010..fd1e292 100644 --- a/src/gas/gas.posix.cc +++ b/src/gas/gas.posix.cc @@ -10,6 +10,12 @@ using namespace xamarin::android::gas; +void Gas::dump_command_line_args ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) +{} + +void Gas::platform_setup() +{} + void Gas::determine_program_dir (std::vector args) { fs::path program_path { args[0] }; diff --git a/src/gas/gas.windows.cc b/src/gas/gas.windows.cc index e421539..3b72424 100644 --- a/src/gas/gas.windows.cc +++ b/src/gas/gas.windows.cc @@ -2,9 +2,13 @@ #include #include +#include +#include #include #include #include +#include +#include #include "exceptions.hh" #include "gas.hh" @@ -12,6 +16,65 @@ using namespace xamarin::android::gas; +namespace { + void log_cp_info(std::wstring label, UINT cp) + { + std::wcout << L" " << label << L" code page:" << std::endl; + std::wcout << L" ID: " << cp << std::endl; + + CPINFOEX cpinfo; + BOOL result = GetCPInfoEx(cp, 0, &cpinfo); + if (!result) { + std::wcout << L" failed to obtain more information about the code page" << std::endl; + return; + } + + std::wcout + << L" Maximum character size: " << cpinfo.MaxCharSize << std::endl + << L" Localized name: " << cpinfo.CodePageName << std::endl; + } + + void log_cli_arg(int index, const wchar_t* arg) + { + std::wcout << L" [" << index << L"] " << std::endl; + std::wcout << std::endl; + std::wstring ws(arg); + std::wcout << L" As C string (direct): " << ws << std::endl; + std::wcout << L" As hex bytes: " << std::hex << std::setw(4) << std::setfill(L'0'); + + const wchar_t* p = arg; + while (p != nullptr && *p != 0) { + auto ch = static_cast(*p); + std::wcout << ch << " "; + p++; + } + std::wcout << std::endl; + } +} + +void Gas::dump_command_line_args (int argc, wchar_t **argv) +{ + std::wcout << L"Active code pages information" << std::endl; + log_cp_info(L"OS", GetACP()); + std::wcout << std::endl; + log_cp_info(L"OEM", GetOEMCP()); + std::wcout << std::endl; + + std::wcout << L"Command line arguments (" << argc << "):" << std::endl; + for (int i = 0; i < argc; i++) { + log_cli_arg(i, argv[i]); + } + std::wcout << L"================================" << std::endl << std::endl; +} + +void Gas::platform_setup() +{ + // Windows needs that magic to make stdout work with wchar_t and friends + constexpr char cp_utf16le[] = ".1200"; // UTF-16 little-endian locale. + setlocale(LC_ALL, cp_utf16le); + _setmode(_fileno(stdout), _O_WTEXT); +} + void Gas::determine_program_dir (std::vector args) { TCHAR buffer[MAX_PATH + 1]{}; diff --git a/src/gas/llvm_mc_runner.cc b/src/gas/llvm_mc_runner.cc index 965fc94..49f75cf 100644 --- a/src/gas/llvm_mc_runner.cc +++ b/src/gas/llvm_mc_runner.cc @@ -26,7 +26,7 @@ std::unordered_map LlvmMcRunner::known_options { int LlvmMcRunner::run (fs::path const& executable_path) { if (!fs::exists (executable_path)) { - STDERR << "Executable '" << executable_path.string () << "' does not exist." << Constants::newline; + STDERR << "Executable '" << executable_path.native () << "' does not exist." << Constants::newline; return Constants::wrapper_exec_failed_error_code; } @@ -59,8 +59,8 @@ int LlvmMcRunner::run (fs::path const& executable_path) process->append_program_argument (PSTR("-o"), opt->second); } - platform::string input_file { PSTR("\"") + input_file_path.make_preferred ().string () + PSTR("\"") }; - process->append_program_argument (input_file_path.make_preferred ().string ()); + platform::string input_file { PSTR("\"") + input_file_path.make_preferred ().native () + PSTR("\"") }; + process->append_program_argument (input_file_path.make_preferred ().native ()); return process->run (); } diff --git a/src/gas/llvm_mc_runner.hh b/src/gas/llvm_mc_runner.hh index afb7cd5..f83ece9 100644 --- a/src/gas/llvm_mc_runner.hh +++ b/src/gas/llvm_mc_runner.hh @@ -68,7 +68,7 @@ namespace xamarin::android::gas void set_output_file_path (fs::path const& file_path) { - set_option (LlvmMcArgument::Output, file_path.string ()); + set_option (LlvmMcArgument::Output, file_path.native ()); } void add_include_path (fs::path const& include_path) @@ -77,7 +77,7 @@ namespace xamarin::android::gas return; } - set_option (LlvmMcArgument::IncludeDir, include_path.string ()); + set_option (LlvmMcArgument::IncludeDir, include_path.native ()); } void generate_debug_info () diff --git a/src/gas/main.cc b/src/gas/main.cc index aca2ea8..f41c6dd 100644 --- a/src/gas/main.cc +++ b/src/gas/main.cc @@ -1,12 +1,16 @@ // SPDX-License-Identifier: MIT -#include #include #include "gas.hh" #include "platform.hh" +#if defined(_WIN32) +int wmain (int argc, wchar_t **argv) +#else int main (int argc, char **argv) +#endif { + xamarin::android::gas::Gas::platform_setup (); xamarin::android::gas::Gas app; std::vector args = app.get_command_line (argc, argv); diff --git a/src/gas/platform.hh b/src/gas/platform.hh index 80d241f..211c476 100644 --- a/src/gas/platform.hh +++ b/src/gas/platform.hh @@ -6,21 +6,23 @@ #include #if defined(_WIN32) -#define STDOUT std::cout -#define STDERR std::cerr -#define PSTR(_str_lit_) (_str_lit_) -#define PCHAR(_ch_) (_ch_) +#define STDOUT std::wcout +#define STDERR std::wcerr +#define PSTR(_str_lit_) (L ## _str_lit_) +#define PCHAR(_ch_) (L ## _ch_) +using argv_char = wchar_t; #else #define STDOUT std::cout #define STDERR std::cerr #define PSTR(_str_lit_) (_str_lit_) #define PCHAR(_ch_) (_ch_) +using argv_char = char; #endif namespace platform { -#if !defined (_WIN32) - using string = std::string; - using string_view = std::string_view; +#if defined (_WIN32) + using string = std::wstring; + using string_view = std::wstring_view; #else using string = std::string; using string_view = std::string_view; diff --git a/src/gas/process.windows.cc b/src/gas/process.windows.cc index 7edb57b..3953ad9 100644 --- a/src/gas/process.windows.cc +++ b/src/gas/process.windows.cc @@ -49,7 +49,7 @@ int Process::run (bool print_command_line) print_process_command_line (); } - platform::string binary = executable_path.string (); + platform::string binary = executable_path.native (); platform::string args { escape_argument (binary) }; for (platform::string const& a : _args) { if (a.empty ()) { @@ -59,21 +59,14 @@ int Process::run (bool print_command_line) args.append (escape_argument (a)); } - int size = MultiByteToWideChar (CP_UTF8, 0, args.c_str (), -1, NULL , 0); - wchar_t* wargs = new wchar_t [size]; - MultiByteToWideChar (CP_UTF8, 0, args.c_str (), -1, wargs, size); - - size = MultiByteToWideChar (CP_UTF8, 0, binary.c_str (), -1, NULL , 0); - wchar_t* wbinary = new wchar_t [size]; - MultiByteToWideChar (CP_UTF8, 0, binary.c_str (), -1, wbinary, size); - PROCESS_INFORMATION pi {}; STARTUPINFOW si {}; si.cb = sizeof(si); DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT; + wchar_t* wargs = _wcsdup(args.c_str()); BOOL success = CreateProcessW ( - wbinary, + binary.c_str (), wargs, nullptr, // process security attributes nullptr, // primary thread security attributes @@ -84,24 +77,28 @@ int Process::run (bool print_command_line) &si, &pi ); - - delete[] wargs; - delete[] wbinary; + free (wargs); if (!success) { return Constants::wrapper_exec_failed_error_code; } // TODO: error handling below + int ret = 0; DWORD result = WaitForSingleObject (pi.hProcess, INFINITE); if (result == 0) { DWORD retcode = 0; if (GetExitCodeProcess (pi.hProcess, &retcode)) { - return retcode; + ret = retcode; + } else { + ret = 128; } - - return 128; + } else { + ret = 1; } - return 1; + CloseHandle (pi.hProcess); + CloseHandle (pi.hThread); + + return ret; }