From 7eca85315879ea0ffd4cd83d8e754c8d36248f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Tue, 13 Aug 2024 10:26:15 +1000 Subject: [PATCH 01/32] Use abort() for NOTREACHED() This annotates NOTREACHED() as [[noreturn]], matching chromium. Bug: 40580068 Change-Id: If13ec8b488457aa7424bcd7d76dc3bd2830551b1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5775483 Reviewed-by: Mark Mentovai --- base/notreached.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/base/notreached.h b/base/notreached.h index 49cf862..72380cf 100644 --- a/base/notreached.h +++ b/base/notreached.h @@ -5,15 +5,15 @@ #ifndef MINI_CHROMIUM_BASE_NOTREACHED_H_ #define MINI_CHROMIUM_BASE_NOTREACHED_H_ +#include + #include "base/check.h" -// TODO(crbug.com/40580068): Redefine NOTREACHED() to be [[noreturn]] once -// Crashpad and Chromium have migrated off of the non-noreturn version. This is -// easiest done by defining it as std::abort() as Crashpad currently doesn't -// stream arguments to it. For a more complete implementation we should use -// LOG(FATAL) but that is currently not annotated as [[noreturn]] because -// ~LogMessage is not. See TODO in base/logging.h -#define NOTREACHED() DCHECK(false) +// Using abort() for NOTREACHED() doesn't support streaming arguments. For a +// more complete implementation we could use LOG(FATAL) but that is currently +// not annotated as [[noreturn]] because ~LogMessage is not. See TODO in +// base/logging.h. +#define NOTREACHED() abort() // TODO(crbug.com/40580068): Remove this once the NotReachedIsFatal experiment // has been rolled out in Chromium. From 61e2124bd6269833afc8c1e8ee9faa7fcf1bd954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Tue, 13 Aug 2024 13:50:20 +1000 Subject: [PATCH 02/32] Remove NOTREACHED_IN_MIGRATION() This is no longer referenced in crashpad. Bug: 40580068 Change-Id: I7c3d955279c791a8e9895c73820264efeb48ee9c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5782432 Reviewed-by: Mark Mentovai --- base/notreached.h | 4 ---- base/threading/thread_local_storage.cc | 6 ++---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/base/notreached.h b/base/notreached.h index 72380cf..c7d73fa 100644 --- a/base/notreached.h +++ b/base/notreached.h @@ -15,8 +15,4 @@ // base/logging.h. #define NOTREACHED() abort() -// TODO(crbug.com/40580068): Remove this once the NotReachedIsFatal experiment -// has been rolled out in Chromium. -#define NOTREACHED_IN_MIGRATION() DCHECK(false) - #endif // MINI_CHROMIUM_BASE_NOTREACHED_H_ diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc index 8aa6c11..7ae9b25 100644 --- a/base/threading/thread_local_storage.cc +++ b/base/threading/thread_local_storage.cc @@ -160,10 +160,8 @@ void OnThreadExitInternal(void* value) { // the whole vector again. This is a pthread standard. need_to_scan_destructors = true; } - if (--remaining_attempts <= 0) { - NOTREACHED_IN_MIGRATION(); // Destructors might not have been called. - break; - } + // Destructors might not have been called. + CHECK_GT(--remaining_attempts, 0); } // Remove our stack allocated vector. From feb7c0812addcee7f550e61956a1ccaa990fe292 Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Wed, 21 Aug 2024 17:46:10 -0700 Subject: [PATCH 03/32] Move/remove macros in compiler_specific.h to match Chromium. * [UN]LIKELY: https://crrev.com/c/5734517 * CDECL: https://crrev.com/c/5803679 * Arch-specific macros: https://crrev.com/c/5805706 * ALIGNAS: https://crrev.com/c/5805902 Bug: none Change-Id: I863e7cedb86e7a471cfe4c551aef11c87b477627 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5804535 Reviewed-by: Mark Mentovai --- base/compiler_specific.h | 62 ---------------------------------------- build/build_config.h | 20 +++++++++++++ 2 files changed, 20 insertions(+), 62 deletions(-) diff --git a/base/compiler_specific.h b/base/compiler_specific.h index f419c42..9a6846e 100644 --- a/base/compiler_specific.h +++ b/base/compiler_specific.h @@ -80,24 +80,6 @@ #define NOT_TAIL_CALLED #endif -// Specify memory alignment for structs, classes, etc. -// Use like: -// class ALIGNAS(16) MyClass { ... } -// ALIGNAS(16) int array[4]; -// -// In most places you can use the C++11 keyword "alignas", which is preferred. -// -// Historically, compilers had trouble mixing __attribute__((...)) syntax with -// alignas(...) syntax. However, at least Clang is very accepting nowadays. It -// may be that this macro can be removed entirely. -#if defined(__clang__) -#define ALIGNAS(byte_alignment) alignas(byte_alignment) -#elif defined(COMPILER_MSVC) -#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) -#elif defined(COMPILER_GCC) && HAS_ATTRIBUTE(aligned) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#endif - // In case the compiler supports it NO_UNIQUE_ADDRESS evaluates to the C++20 // attribute [[no_unique_address]]. This allows annotating data members so that // they need not have an address distinct from all other non-static data members @@ -205,32 +187,6 @@ #define DISABLE_CFI_DLSYM #endif -// Macro useful for writing cross-platform function pointers. -#if !defined(CDECL) -#if BUILDFLAG(IS_WIN) -#define CDECL __cdecl -#else // BUILDFLAG(IS_WIN) -#define CDECL -#endif // BUILDFLAG(IS_WIN) -#endif // !defined(CDECL) - -// Macro for hinting that an expression is likely to be false. -#if !defined(UNLIKELY) -#if defined(COMPILER_GCC) || defined(__clang__) -#define UNLIKELY(x) __builtin_expect(!!(x), 0) -#else -#define UNLIKELY(x) (x) -#endif // defined(COMPILER_GCC) -#endif // !defined(UNLIKELY) - -#if !defined(LIKELY) -#if defined(COMPILER_GCC) || defined(__clang__) -#define LIKELY(x) __builtin_expect(!!(x), 1) -#else -#define LIKELY(x) (x) -#endif // defined(COMPILER_GCC) -#endif // !defined(LIKELY) - // Compiler feature-detection. // clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension #if defined(__has_feature) @@ -248,24 +204,6 @@ #define PRETTY_FUNCTION __func__ #endif -#if !defined(CPU_ARM_NEON) -#if defined(__arm__) -#if !defined(__ARMEB__) && !defined(__ARM_EABI__) && !defined(__EABI__) && \ - !defined(__VFP_FP__) && !defined(_WIN32_WCE) && !defined(ANDROID) -#error Chromium does not support middle endian architecture -#endif -#if defined(__ARM_NEON__) -#define CPU_ARM_NEON 1 -#endif -#endif // defined(__arm__) -#endif // !defined(CPU_ARM_NEON) - -#if !defined(HAVE_MIPS_MSA_INTRINSICS) -#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) -#define HAVE_MIPS_MSA_INTRINSICS 1 -#endif -#endif - #if defined(__clang__) && HAS_ATTRIBUTE(uninitialized) // Attribute "uninitialized" disables -ftrivial-auto-var-init=pattern for // the specified variable. diff --git a/build/build_config.h b/build/build_config.h index 6252745..b8eb1f9 100644 --- a/build/build_config.h +++ b/build/build_config.h @@ -141,4 +141,24 @@ #error Please add support for your compiler in build/build_config.h #endif +// Architecture-specific feature detection. + +#if !defined(CPU_ARM_NEON) +#if defined(__arm__) +#if !defined(__ARMEB__) && !defined(__ARM_EABI__) && !defined(__EABI__) && \ + !defined(__VFP_FP__) && !defined(_WIN32_WCE) && !defined(ANDROID) +#error Chromium does not support middle endian architecture +#endif +#if defined(__ARM_NEON__) +#define CPU_ARM_NEON 1 +#endif +#endif // defined(__arm__) +#endif // !defined(CPU_ARM_NEON) + +#if !defined(HAVE_MIPS_MSA_INTRINSICS) +#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5) +#define HAVE_MIPS_MSA_INTRINSICS 1 +#endif +#endif + #endif // MINI_CHROMIUM_BUILD_BUILD_CONFIG_H_ From e04c707cb33a876b595a9b8be7aa284c6b536afa Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Wed, 21 Aug 2024 18:02:29 -0700 Subject: [PATCH 04/32] Remove `WPRINTF_FORMAT`. Matches https://crrev.com/c/5805924. Bug: none Change-Id: If96d8ecbc227247d436427cda88d3d6aabe8f40e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5804790 Reviewed-by: Mark Mentovai --- base/compiler_specific.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/base/compiler_specific.h b/base/compiler_specific.h index 9a6846e..c3eb41a 100644 --- a/base/compiler_specific.h +++ b/base/compiler_specific.h @@ -113,13 +113,6 @@ #define PRINTF_FORMAT(format_param, dots_param) #endif -// WPRINTF_FORMAT is the same, but for wide format strings. -// This doesn't appear to yet be implemented in any compiler. -// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 . -#define WPRINTF_FORMAT(format_param, dots_param) -// If available, it would look like: -// __attribute__((format(wprintf, format_param, dots_param))) - // Sanitizers annotations. #if HAS_ATTRIBUTE(no_sanitize) #define NO_SANITIZE(what) __attribute__((no_sanitize(what))) From 4027559ee0df2d8f43de5e8672cf525a40884545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Thu, 3 Oct 2024 10:52:50 +1000 Subject: [PATCH 05/32] Make LOG(FATAL) [[noreturn]] This also changes NOTREACHED() to use LOG(FATAL) which both enables log streaming and printing something useful when hit. Bug: chromium:40254046 Change-Id: I187da25fe42f67dbf06f1e5a8c507e6b8cc46d6e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5904318 Reviewed-by: Mark Mentovai --- base/apple/mach_logging.cc | 21 ++++++++++++++++++ base/apple/mach_logging.h | 18 +++++++++++++++ base/fuchsia/fuchsia_logging.cc | 10 +++++++++ base/fuchsia/fuchsia_logging.h | 9 ++++++++ base/logging.cc | 25 +++++++++++++++++++++ base/logging.h | 39 +++++++++++++++++++++++++++++---- base/notreached.h | 9 ++------ 7 files changed, 120 insertions(+), 11 deletions(-) diff --git a/base/apple/mach_logging.cc b/base/apple/mach_logging.cc index d5d5198..0083aca 100644 --- a/base/apple/mach_logging.cc +++ b/base/apple/mach_logging.cc @@ -7,6 +7,7 @@ #include #include +#include "base/immediate_crash.h" #include "base/strings/stringprintf.h" #if !BUILDFLAG(IS_IOS) @@ -37,10 +38,20 @@ MachLogMessage::MachLogMessage(const char* function, : LogMessage(function, file_path, line, severity), mach_err_(mach_err) {} MachLogMessage::~MachLogMessage() { + AppendError(); +} + +void MachLogMessage::AppendError() { stream() << ": " << mach_error_string(mach_err_) << FormatMachErrorNumber(mach_err_); } +MachLogMessageFatal::~MachLogMessageFatal() { + AppendError(); + Flush(); + base::ImmediateCrash(); +} + #if !BUILDFLAG(IS_IOS) BootstrapLogMessage::BootstrapLogMessage(const char* function, @@ -52,6 +63,10 @@ BootstrapLogMessage::BootstrapLogMessage(const char* function, bootstrap_err_(bootstrap_err) {} BootstrapLogMessage::~BootstrapLogMessage() { + AppendError(); +} + +void BootstrapLogMessage::AppendError() { stream() << ": " << bootstrap_strerror(bootstrap_err_); switch (bootstrap_err_) { @@ -79,6 +94,12 @@ BootstrapLogMessage::~BootstrapLogMessage() { } } +BootstrapLogMessageFatal::~BootstrapLogMessageFatal() { + AppendError(); + Flush(); + base::ImmediateCrash(); +} + #endif // !BUILDFLAG(IS_IOS) } // namespace logging diff --git a/base/apple/mach_logging.h b/base/apple/mach_logging.h index 9ba89b4..5ca9216 100644 --- a/base/apple/mach_logging.h +++ b/base/apple/mach_logging.h @@ -44,10 +44,19 @@ class MachLogMessage : public logging::LogMessage { ~MachLogMessage(); + protected: + void AppendError(); + private: mach_error_t mach_err_; }; +class MachLogMessageFatal final : public MachLogMessage { + public: + using MachLogMessage::MachLogMessage; + [[noreturn]] ~MachLogMessageFatal() override; +}; + } // namespace logging #define MACH_LOG_STREAM(severity, mach_err) \ @@ -108,10 +117,19 @@ class BootstrapLogMessage : public logging::LogMessage { ~BootstrapLogMessage(); + protected: + void AppendError(); + private: kern_return_t bootstrap_err_; }; +class BootstrapLogMessageFatal final : public BootstrapLogMessage { + public: + using BootstrapLogMessage::BootstrapLogMessage; + [[noreturn]] ~BootstrapLogMessageFatal() override; +}; + } // namespace logging #define BOOTSTRAP_LOG_STREAM(severity, bootstrap_err) \ diff --git a/base/fuchsia/fuchsia_logging.cc b/base/fuchsia/fuchsia_logging.cc index 12dca72..a5af506 100644 --- a/base/fuchsia/fuchsia_logging.cc +++ b/base/fuchsia/fuchsia_logging.cc @@ -18,10 +18,20 @@ ZxLogMessage::ZxLogMessage(const char* function, : LogMessage(function, file_path, line, severity), zx_err_(zx_err) {} ZxLogMessage::~ZxLogMessage() { + AppendError(); +} + +void ZxLogMessage::AppendError() { // zx_status_t error values are negative, so log the numeric version as // decimal rather than hex. This is also useful to match zircon/errors.h for // grepping. stream() << ": " << zx_status_get_string(zx_err_) << " (" << zx_err_ << ")"; } +ZxLogMessageFatal::~ZxLogMessageFatal() { + AppendError(); + Flush(); + base::ImmediateCrash(); +} + } // namespace logging diff --git a/base/fuchsia/fuchsia_logging.h b/base/fuchsia/fuchsia_logging.h index 3f70cac..0f1e95d 100644 --- a/base/fuchsia/fuchsia_logging.h +++ b/base/fuchsia/fuchsia_logging.h @@ -28,10 +28,19 @@ class ZxLogMessage : public logging::LogMessage { ~ZxLogMessage(); + protected: + void AppendError(); + private: zx_status_t zx_err_; }; +class ZxLogMessageFatal final : public ZxLogMessage { + public: + using ZxLogMessage::ZxLogMessage; + [[noreturn]] ~ZxLogMessageFatal() override; +}; + } // namespace logging #define ZX_LOG_STREAM(severity, zx_err) \ diff --git a/base/logging.cc b/base/logging.cc index 959b64f..ab5b0cf 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -476,6 +476,11 @@ void LogMessage::Init(const char* function) { message_start_ = stream_.str().size(); } +LogMessageFatal::~LogMessageFatal() { + Flush(); + base::ImmediateCrash(); +} + #if BUILDFLAG(IS_WIN) unsigned long GetLastSystemErrorCode() { @@ -491,9 +496,19 @@ Win32ErrorLogMessage::Win32ErrorLogMessage(const char* function, } Win32ErrorLogMessage::~Win32ErrorLogMessage() { + AppendError(); +} + +void Win32ErrorLogMessage::AppendError() { stream() << ": " << SystemErrorCodeToString(err_); } +Win32ErrorLogMessageFatal::~Win32ErrorLogMessageFatal() { + AppendError(); + Flush(); + base::ImmediateCrash(); +} + #elif BUILDFLAG(IS_POSIX) ErrnoLogMessage::ErrnoLogMessage(const char* function, @@ -506,6 +521,10 @@ ErrnoLogMessage::ErrnoLogMessage(const char* function, } ErrnoLogMessage::~ErrnoLogMessage() { + AppendError(); +} + +void ErrnoLogMessage::AppendError() { stream() << ": " << base::safe_strerror(err_) << " (" @@ -513,6 +532,12 @@ ErrnoLogMessage::~ErrnoLogMessage() { << ")"; } +ErrnoLogMessageFatal::~ErrnoLogMessageFatal() { + AppendError(); + Flush(); + base::ImmediateCrash(); +} + #endif // BUILDFLAG(IS_POSIX) } // namespace logging diff --git a/base/logging.h b/base/logging.h index 30fb2d6..d5c58cf 100644 --- a/base/logging.h +++ b/base/logging.h @@ -123,6 +123,12 @@ class LogMessage { LogSeverity severity_; }; +class LogMessageFatal final : public LogMessage { + public: + using LogMessage::LogMessage; + [[noreturn]] ~LogMessageFatal() override; +}; + class LogMessageVoidify { public: LogMessageVoidify() {} @@ -144,9 +150,19 @@ class Win32ErrorLogMessage : public LogMessage { ~Win32ErrorLogMessage(); + protected: + void AppendError(); + private: unsigned long err_; }; + +class Win32ErrorLogMessageFatal final : public Win32ErrorLogMessage { + public: + using Win32ErrorLogMessage::Win32ErrorLogMessage; + [[noreturn]] ~Win32ErrorLogMessageFatal() override; +}; + #elif BUILDFLAG(IS_POSIX) class ErrnoLogMessage : public LogMessage { public: @@ -161,9 +177,18 @@ class ErrnoLogMessage : public LogMessage { ~ErrnoLogMessage(); + protected: + void AppendError(); + private: int err_; }; + +class ErrnoLogMessageFatal final : public ErrnoLogMessage { + public: + using ErrnoLogMessage::ErrnoLogMessage; + [[noreturn]] ~ErrnoLogMessageFatal() override; +}; #endif } // namespace logging @@ -187,8 +212,11 @@ class ErrnoLogMessage : public LogMessage { logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \ logging::LOG_ERROR_REPORT, ## __VA_ARGS__) #define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \ - logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \ - logging::LOG_FATAL, ## __VA_ARGS__) + logging::ClassName##Fatal(FUNCTION_SIGNATURE, \ + __FILE__, \ + __LINE__, \ + logging::LOG_FATAL, \ + ##__VA_ARGS__) #define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \ logging::ClassName(FUNCTION_SIGNATURE, __FILE__, __LINE__, \ logging::LOG_DFATAL, ## __VA_ARGS__) @@ -230,8 +258,11 @@ const LogSeverity LOG_0 = LOG_ERROR; #define LAZY_STREAM(stream, condition) \ !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream) -#define LOG_IS_ON(severity) \ - ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel()) +// FATAL is always enabled and required to be resolved in compile time for +// LOG(FATAL) to be properly understood as [[noreturn]]. +#define LOG_IS_ON(severity) \ + ((::logging::LOG_##severity) == ::logging::LOG_FATAL || \ + (::logging::LOG_##severity) >= ::logging::GetMinLogLevel()) #define VLOG_IS_ON(verbose_level) \ ((verbose_level) <= ::logging::GetVlogLevel(__FILE__)) diff --git a/base/notreached.h b/base/notreached.h index c7d73fa..9c40c1f 100644 --- a/base/notreached.h +++ b/base/notreached.h @@ -5,14 +5,9 @@ #ifndef MINI_CHROMIUM_BASE_NOTREACHED_H_ #define MINI_CHROMIUM_BASE_NOTREACHED_H_ -#include - #include "base/check.h" +#include "base/logging.h" -// Using abort() for NOTREACHED() doesn't support streaming arguments. For a -// more complete implementation we could use LOG(FATAL) but that is currently -// not annotated as [[noreturn]] because ~LogMessage is not. See TODO in -// base/logging.h. -#define NOTREACHED() abort() +#define NOTREACHED() LOG(FATAL) << "NOTREACHED hit. " #endif // MINI_CHROMIUM_BASE_NOTREACHED_H_ From d288241f0e8cd12aaede01de9ceae786e81527b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Thu, 3 Oct 2024 13:02:50 +1000 Subject: [PATCH 06/32] Fix LOG(FATAL) compile errors This disables C4722 for intentionally-[[noreturn]] destructors and IWYUs base/immediate_crash.h for fuchsia_logging.cc. Bug: chromium:40254046 Change-Id: I9df3ab96d4d6489485bca55748dfe806a1f0f444 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5907038 Reviewed-by: Mark Mentovai --- base/fuchsia/fuchsia_logging.cc | 2 ++ base/logging.cc | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/base/fuchsia/fuchsia_logging.cc b/base/fuchsia/fuchsia_logging.cc index a5af506..10d881b 100644 --- a/base/fuchsia/fuchsia_logging.cc +++ b/base/fuchsia/fuchsia_logging.cc @@ -8,6 +8,8 @@ #include +#include "base/immediate_crash.h" + namespace logging { ZxLogMessage::ZxLogMessage(const char* function, diff --git a/base/logging.cc b/base/logging.cc index ab5b0cf..0385767 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -476,11 +476,22 @@ void LogMessage::Init(const char* function) { message_start_ = stream_.str().size(); } +// We intentionally don't return from these destructors. Disable MSVC's warning +// about the destructor never returning as we do so intentionally here. +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +#pragma warning(disable : 4722) +#endif + LogMessageFatal::~LogMessageFatal() { Flush(); base::ImmediateCrash(); } +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif + #if BUILDFLAG(IS_WIN) unsigned long GetLastSystemErrorCode() { @@ -503,12 +514,23 @@ void Win32ErrorLogMessage::AppendError() { stream() << ": " << SystemErrorCodeToString(err_); } +// We intentionally don't return from these destructors. Disable MSVC's warning +// about the destructor never returning as we do so intentionally here. +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) +#pragma warning(disable : 4722) +#endif + Win32ErrorLogMessageFatal::~Win32ErrorLogMessageFatal() { AppendError(); Flush(); base::ImmediateCrash(); } +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) +#endif + #elif BUILDFLAG(IS_POSIX) ErrnoLogMessage::ErrnoLogMessage(const char* function, From c081fd005b09a59a505b09a4b506f8ba45f70859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Thu, 3 Oct 2024 14:42:45 +1000 Subject: [PATCH 07/32] Reimplement LAZY_STREAM with a switch This trades warnings with C4715 (not all control paths return a value) and C4127 (conditional expression is constant). We explicitly disable C4127 so fingers crossed that no other problem pops up when rolling this into crashpad. This also gets rid of logging::LogMessageVoidify which is nice. Bug: chromium:40254046 Change-Id: I52274f3e66d84507c48f019a66ebabebe80ca912 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/5907040 Reviewed-by: Mark Mentovai --- base/logging.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/base/logging.h b/base/logging.h index d5c58cf..244d6a9 100644 --- a/base/logging.h +++ b/base/logging.h @@ -129,13 +129,6 @@ class LogMessageFatal final : public LogMessage { [[noreturn]] ~LogMessageFatal() override; }; -class LogMessageVoidify { - public: - LogMessageVoidify() {} - - void operator&(const std::ostream&) const {} -}; - #if BUILDFLAG(IS_WIN) class Win32ErrorLogMessage : public LogMessage { public: @@ -256,7 +249,13 @@ const LogSeverity LOG_0 = LOG_ERROR; #endif // BUILDFLAG(IS_WIN) #define LAZY_STREAM(stream, condition) \ - !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream) + switch (0) \ + case 0: \ + default: \ + if (!(condition)) \ + ; \ + else \ + (stream) // FATAL is always enabled and required to be resolved in compile time for // LOG(FATAL) to be properly understood as [[noreturn]]. From c4bcfd045d8dab7f78c7e17a74672e3509a1f182 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 12 Nov 2024 11:09:34 -0500 Subject: [PATCH 08/32] #include for size_t Change-Id: I714c3fde7579a43faf30973fcc0d7f3cb5e7227a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6011592 Reviewed-by: Joshua Peraza --- base/template_util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/template_util.h b/base/template_util.h index 7fce811..5b6e0d4 100644 --- a/base/template_util.h +++ b/base/template_util.h @@ -5,6 +5,8 @@ #ifndef MINI_CHROMIUM_BASE_TEMPLATE_UTIL_H_ #define MINI_CHROMIUM_BASE_TEMPLATE_UTIL_H_ +#include + #include namespace base { From ec9a9b4a61fb6ba9d6534da13ebf8c41e83c99c6 Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Thu, 12 Dec 2024 09:09:26 -0800 Subject: [PATCH 09/32] Add fixed_extent to base::span. This is done in a more localized way than upstream, where we support IntegralConstantLike in StrictNumeric. Bug: none Change-Id: Ia2a5f086fec0d318f168774aad717805eed25a35 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6090877 Reviewed-by: Mark Mentovai --- base/containers/span.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/base/containers/span.h b/base/containers/span.h index c7ed4c3..a34d2ee 100644 --- a/base/containers/span.h +++ b/base/containers/span.h @@ -33,6 +33,9 @@ namespace base { +template +using fixed_extent = std::integral_constant; + template @@ -40,6 +43,21 @@ class span; namespace internal { +template +concept IntegralConstantLike = + std::is_integral_v && + !std::is_same_v> && + std::convertible_to && + std::equality_comparable_with && + std::bool_constant::value && + std::bool_constant(T()) == T::value>::value; + +template +inline constexpr size_t MaybeStaticExt = dynamic_extent; +template + requires IntegralConstantLike +inline constexpr size_t MaybeStaticExt = {T::value}; + template concept LegalDataConversion = std::convertible_to (*)[], @@ -260,6 +278,13 @@ class GSL_POINTER span { requires(N == 0) = default; + template + requires(internal::CompatibleIter) + UNSAFE_BUFFER_USAGE explicit constexpr span( + It first, + std::integral_constant count) noexcept + : span(first, N) {} + // Constructs a span from a contiguous iterator and a size. // // # Checks @@ -1038,7 +1063,8 @@ class GSL_POINTER span { // [span.deduct], deduction guides. template requires(std::contiguous_iterator) -span(It, EndOrSize) -> span>>; +span(It, EndOrSize) -> span>, + internal::MaybeStaticExt>; template < typename R, From 63057a19a3fe9973d3f1fca72b68bb9a27d7f162 Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Thu, 12 Dec 2024 11:57:22 -0800 Subject: [PATCH 10/32] Fix template param shadowing. Bug: none Change-Id: I531fb132349814214896ac8af9734a75b873f4d8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6092430 Reviewed-by: Mark Mentovai --- base/containers/span.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/containers/span.h b/base/containers/span.h index a34d2ee..6b02cfa 100644 --- a/base/containers/span.h +++ b/base/containers/span.h @@ -278,12 +278,12 @@ class GSL_POINTER span { requires(N == 0) = default; - template + template requires(internal::CompatibleIter) UNSAFE_BUFFER_USAGE explicit constexpr span( It first, - std::integral_constant count) noexcept - : span(first, N) {} + std::integral_constant count) noexcept + : span(first, M) {} // Constructs a span from a contiguous iterator and a size. // From 22f743de47b7d14d824092c4803fc1288ab07367 Mon Sep 17 00:00:00 2001 From: Leonard Grey Date: Tue, 17 Dec 2024 16:33:52 -0500 Subject: [PATCH 11/32] Remove distutils dependency `distutils` is removed in Python 3.12+. Changed to adapt the approach in maxi-Chromium's `build/mac/find_sdk.py` Bug: None Change-Id: Ia2beb098b822ef5b09d1fe2048a310fcdaa0cf95 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6097742 Reviewed-by: Mark Mentovai --- build/find_mac_sdk.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/find_mac_sdk.py b/build/find_mac_sdk.py index 582c118..70b3771 100755 --- a/build/find_mac_sdk.py +++ b/build/find_mac_sdk.py @@ -8,7 +8,6 @@ from __future__ import print_function import argparse -import distutils.version import os import re import subprocess @@ -16,8 +15,8 @@ import textwrap -def _AsVersion(string): - return distutils.version.StrictVersion(string) +def _AsVersion(version_str): + return tuple((int(s) for s in re.findall(r'(\d+)', version_str))) def _RunXCRun(args, sdk=None): From 12ef786772d9a73751e2d0f3ef9c792b09c386b5 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 17 Jan 2025 11:56:18 -0500 Subject: [PATCH 12/32] OWN mini_chromium Bug: 390190633 Change-Id: I60eb0804cea4f1151782943e2402e5a1a11a554b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6180421 Reviewed-by: Joshua Peraza Reviewed-by: Justin Cohen Reviewed-by: Joey Scarr --- OWNERS | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 OWNERS diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..e4ca129 --- /dev/null +++ b/OWNERS @@ -0,0 +1,12 @@ +# Copyright 2025 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +set noparent + +jperaza@chromium.org +justincohen@chromium.org +lgrey@chromium.org +mark@chromium.org +pbos@chromium.org +wfh@chromium.org From 08d490553b0dcb1324efb59b13be839d7f9f3b62 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 13 Feb 2025 13:30:01 -0500 Subject: [PATCH 13/32] Prepare mini_chromium for using clang on Windows This does several things to prepare for using clang on Windows: * It makes `mini_chromium_is_clang` a GN arg on Windows, so that it's possible to opt in to using clang via args.gn. (It doesn't change the default yet, and once the default is flipped, we can make it not an arg again.) * It stops passing a few cl.exe flags to the compiler if clang is being used. clang-cl supports most of cl.exe's flags, but it warns about the LTCG flags. It also stops passing a few cl.exe flags that are silently ignored by clang-cl to keep command lines tidier. * It passes a few clang-only flags such as `-m32` on x86. * It passes warning flags that we pass on other platforms to the compiler to clang-cl on Windows too. The important one is `Wno-unused-parameter`: without this, we get hundreds of build warnings. * It also disables a few clang warnings on Windows only. These can be cleaned up and turned on later. * It updates win_helper.py to accept slashes in the path to ml in ExecAsmWrapper, like already done for the linker in ExecLinkWrapper() * Finally, and most importantly, it makes the toolchain call clang-cl, lld-link, and llvm-ml instead of cl.exe, link.exe, and ml.exe. On arm64, we use clang-cl instead of armasm64.exe (matching Chromium). There are several cleanups that can be done with clang that I haven't done yet and am currently not planning on doing: * The ninja -e and ninja -t msvc wrapper processes for cc, cxx, ld, ar, ml can be removed by instead using clang-cl's /winsysroot flag * Once that's done, it should be reasonably straightforward to set up a cross build to enable building crashpad/win on linux * https://blog.llvm.org/2019/11/deterministic-builds-with-clang-and-lld.html describes how to make the build fully deterministic with clang-cl No behavior change, since clang is still off by default. Bug: 384682775 Change-Id: Ie7b16a94c595fdf7e281c6127520b69d380408df Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6261289 Reviewed-by: Mark Mentovai --- build/compiler.gni | 8 ++- build/config/BUILD.gn | 141 ++++++++++++++++++++++++++++++++---------- build/win_helper.py | 11 +++- 3 files changed, 124 insertions(+), 36 deletions(-) diff --git a/build/compiler.gni b/build/compiler.gni index ddaffc8..d0e7614 100644 --- a/build/compiler.gni +++ b/build/compiler.gni @@ -4,4 +4,10 @@ import("platform.gni") -mini_chromium_is_clang = mini_chromium_is_posix || mini_chromium_is_fuchsia +if (mini_chromium_is_win) { + declare_args() { + mini_chromium_is_clang = mini_chromium_is_posix || mini_chromium_is_fuchsia + } +} else { + mini_chromium_is_clang = mini_chromium_is_posix || mini_chromium_is_fuchsia +} diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 0802be8..3751ad9 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -44,6 +44,9 @@ if (mini_chromium_is_mac) { # win_sdk\bin\SetEnv.cmd inside this path will be used to configure the # Windows toolchain. win_toolchain_path = "" + + # Path to the Clang toolchain. + clang_path = "//third_party/windows/clang/" + host_os + "-amd64" } } @@ -108,19 +111,24 @@ config("release") { } } else if (mini_chromium_is_win) { cflags = [ - "/GL", # LTCG. "/O2", "/Ob2", # Both explicit and auto inlining. "/Oy-", # Disable omitting frame pointers, must be after /O2. "/Zc:inline", # Remove unreferenced COMDAT (faster links). - "/d2Zi+", # Improve debugging of optimized code. ] ldflags = [ "/OPT:ICF", "/OPT:REF", - "/LTCG", ] - arflags = [ "/LTCG" ] + arflags = [] + if (!mini_chromium_is_clang) { + cflags += [ + "/GL", # LTCG. + "/d2Zi+", # Improve debugging of optimized code. + ] + ldflags += [ "/LTCG" ] + arflags += [ "/LTCG" ] + } } } @@ -132,17 +140,8 @@ config("default") { if (mini_chromium_is_posix || mini_chromium_is_fuchsia) { cflags = [ "-Wall", - "-Wendif-labels", "-Werror", "-Wextra", - "-Wextra-semi", - "-Wheader-hygiene", - "-Wnewline-eof", - "-Wno-missing-field-initializers", - "-Wno-unused-parameter", - "-Wsign-compare", - "-Wstring-conversion", - "-Wvla", "-fno-exceptions", "-fno-rtti", "-fno-strict-aliasing", # See https://crbug.com/32204 @@ -247,18 +246,33 @@ config("default") { "/WX", "/Zi", "/bigobj", # Support larger number of sections in obj file. - "/wd4100", # Unreferenced formal parameter. - "/wd4127", # Conditional expression is constant. - "/wd4324", # Structure was padded due to alignment specifier. - "/wd4351", # New behavior: elements of array will be default initialized. - "/wd4577", # 'noexcept' used with no exception handling mode specified. "/wd4996", # 'X' was declared deprecated. ] - cflags_cc = [ - "/std:c++20", - "/Zc:__cplusplus", - ] + cflags_cc = [ "/std:c++20" ] + + if (mini_chromium_is_clang) { + if (current_cpu == "x86") { + cflags += [ "--target=i386-pc-windows" ] + } else if (current_cpu == "x64") { + cflags += [ "--target=x86_64-pc-windows" ] + } else if (current_cpu == "arm64") { + cflags += [ "--target=aarch64-pc-windows" ] + } else { + assert(false, "Unsupported architecture") + } + } else { + cflags += [ + "/wd4100", # Unreferenced formal parameter. + "/wd4127", # Conditional expression is constant. + "/wd4324", # Structure was padded due to alignment specifier. + "/wd4351", # elements of array will be default initialized. + "/wd4577", # 'noexcept' used with no exception handling mode specified. + ] + + # This is the default in clang, no need to pass it there. + cflags_cc += [ "/Zc:__cplusplus" ] + } ldflags += [ "/DEBUG" ] @@ -327,6 +341,34 @@ config("default") { ] } + if (mini_chromium_is_posix || mini_chromium_is_fuchsia || + mini_chromium_is_clang) { + cflags += [ + "-Wendif-labels", + "-Wextra-semi", + "-Wheader-hygiene", + "-Wnewline-eof", + "-Wno-missing-field-initializers", + "-Wno-unused-parameter", + "-Wsign-compare", + "-Wstring-conversion", + "-Wvla", + ] + + if (mini_chromium_is_win) { + # TODO: These should be cleaned up and enabled. + cflags += [ + "-Wno-cast-function-type-mismatch", # Currently 22 instances. + "-Wno-format", # Currently 3 instances. + "-Wno-microsoft-cast", # Currently 2 instances. + "-Wno-missing-field-initializers", # Currently 24 instances. + "-Wno-sign-compare", # Currently 6 instances. + "-Wno-unused-const-variable", # Currently 1 instance. + "-Wno-unused-function", # Currently 1 instance. + ] + } + } + if ((mini_chromium_is_posix && !mini_chromium_is_mac && !mini_chromium_is_ios) || mini_chromium_is_fuchsia) { cflags += [ "-fPIC" ] @@ -634,10 +676,17 @@ if (mini_chromium_is_win) { toolchain("msvc_toolchain_$target_name") { # @rsp files are not used for simplicity, and because mini_chromium and # Crashpad shouldn't require them in any configurations. - cc = "cl.exe" - cxx = "cl.exe" - ar = "lib.exe" - ld = "link.exe" + if (mini_chromium_is_clang) { + cc = rebase_path(clang_path, root_build_dir) + "/bin/clang-cl.exe" + cxx = rebase_path(clang_path, root_build_dir) + "/bin/clang-cl.exe" + ar = rebase_path(clang_path, root_build_dir) + "/bin/lld-link.exe /lib" + ld = rebase_path(clang_path, root_build_dir) + "/bin/lld-link.exe" + } else { + cc = "cl.exe" + cxx = "cl.exe" + ar = "lib.exe" + ld = "link.exe" + } lib_switch = "" lib_dir_switch = "/LIBPATH:" env = invoker.environment_file @@ -717,17 +766,43 @@ if (mini_chromium_is_win) { } tool("asm") { - if (invoker.current_cpu == "arm64") { - ml = "armasm64.exe" - command = "$python_path $helper_path asm-wrapper $env $ml {{include_dirs}} {{asmflags}} -o {{output}} {{source}}" + is_msvc_assembler = true + + if (mini_chromium_is_clang) { + if (invoker.current_cpu == "arm64") { + ml = "$cc --target=aarch64-pc-windows -o{{output}} /showIncludes" + is_msvc_assembler = false + depsformat = "msvc" + } else { + ml = rebase_path(clang_path, root_build_dir) + "/bin/llvm-ml.exe" + if (invoker.current_cpu == "x64") { + ml += " -m64" + } else { + ml += " -m32" + } + } } else { - if (invoker.current_cpu == "x86") { - ml = "ml.exe" + if (invoker.current_cpu == "arm64") { + ml = "armasm64.exe" + } if (invoker.current_cpu == "x64") { + ml = "ml64.exe" + } else { + ml = "ml.exe" + } + } + + if (is_msvc_assembler) { + ml += " /nologo /Fo{{output}}" + + if (invoker.current_cpu == "arm64") { + command = "\"$python_path\" $helper_path asm-wrapper $env $ml {{include_dirs}} {{asmflags}} {{source}}" } else { - ml = "ml64.exe" + command = "\"$python_path\" $helper_path asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} /c {{source}}" } - command = "$python_path $helper_path asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} /c /Fo{{output}} {{source}}" + } else { + command = "$ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}" } + description = "ASM {{output}}" outputs = [ "{{source_out_dir}}/{{label_name}}.{{source_name_part}}.obj" ] diff --git a/build/win_helper.py b/build/win_helper.py index be977c8..f4c9d9a 100644 --- a/build/win_helper.py +++ b/build/win_helper.py @@ -114,6 +114,13 @@ def _GetEnvAsDict(arch): return dict(kvs) +def _SlashSlashes(args): + """Returns args as list, with backslashes instead of slashes in args[0].""" + args = list(args) # *args is a tuple by default, which is read-only. + args[0] = args[0].replace('/', '\\') + return args + + class WinTool(object): def Dispatch(self, args): """Dispatches a string command to a method.""" @@ -133,8 +140,7 @@ def ExecLinkWrapper(self, arch, *args): This happens when there are exports from the dll or exe. """ env = _GetEnvAsDict(arch) - args = list(args) # *args is a tuple by default, which is read-only. - args[0] = args[0].replace('/', '\\') + args = _SlashSlashes(args) link = subprocess.Popen(args, env=env, shell=True, stdout=subprocess.PIPE) out, _ = link.communicate() for line in out.splitlines(): @@ -148,6 +154,7 @@ def ExecLinkWrapper(self, arch, *args): def ExecAsmWrapper(self, arch, *args): """Filter logo banner from invocations of asm.exe.""" env = _GetEnvAsDict(arch) + args = _SlashSlashes(args) popen = subprocess.Popen(args, env=env, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, _ = popen.communicate() From a7df8840eb84b532d9ee4f477763f7c47181dfca Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 24 Feb 2025 14:44:27 -0500 Subject: [PATCH 14/32] Enable clang by default on Windows For now, it can still be turned off via a GN arg on Windows. We probably want to remove that soon. Bug: 384682775 Change-Id: I59e2374347e7b39000aaebd1dcf9a35e68d75666 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6298676 Reviewed-by: Mark Mentovai --- build/compiler.gni | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/compiler.gni b/build/compiler.gni index d0e7614..7e2b3ce 100644 --- a/build/compiler.gni +++ b/build/compiler.gni @@ -6,8 +6,10 @@ import("platform.gni") if (mini_chromium_is_win) { declare_args() { - mini_chromium_is_clang = mini_chromium_is_posix || mini_chromium_is_fuchsia + mini_chromium_is_clang = mini_chromium_is_posix || + mini_chromium_is_fuchsia || mini_chromium_is_win } } else { - mini_chromium_is_clang = mini_chromium_is_posix || mini_chromium_is_fuchsia + mini_chromium_is_clang = + mini_chromium_is_posix || mini_chromium_is_fuchsia || mini_chromium_is_win } From cb60252b4173b7bbd2bc3cfea46abf4cd488ad19 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 25 Feb 2025 14:05:11 -0500 Subject: [PATCH 15/32] Run clang arm64 asm under env wrapper I got this wrong in https://chromium-review.googlesource.com/6261289 because I based it on Chromium, and Chromium no longer uses env wrappers. I think this fixes compiling asm files in win/clang/arm64 builds. I cannot check that though as win/arm64 builds seem to be broken earlier in the build for other reasons (both with and without clang). Bug: 384682775 Change-Id: I0b763e76c8e5bc52fe3756aa41e61d6fb1e0d317 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6297640 Reviewed-by: Mark Mentovai --- build/config/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 3751ad9..a3fff85 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -800,7 +800,7 @@ if (mini_chromium_is_win) { command = "\"$python_path\" $helper_path asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} /c {{source}}" } } else { - command = "$ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}" + command = "ninja -t msvc -e $env -- $ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}" } description = "ASM {{output}}" From 107106fe36f6de8318a56d0dd44914486d30ff87 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 26 Feb 2025 15:48:38 -0500 Subject: [PATCH 16/32] Reformat all Python scripts according to Google style I used yapf, and then a followed that up with manual application of automatic reflow of comments and docstrings. I also removed a couple of unused imports, and added a missing #! line. Change-Id: Ie291e05a36844106478e001e28c85d90ca5f254b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6307102 Reviewed-by: Justin Cohen --- build/find_mac_sdk.py | 254 +++--- build/ios/codesign.py | 1211 ++++++++++++++-------------- build/ios/find_signing_identity.py | 115 +-- build/ios/plist_util.py | 418 +++++----- build/ios/sdk_info.py | 249 +++--- build/ios/strip_arm64e.py | 79 +- build/win_helper.py | 418 +++++----- build/write_buildflag_header.py | 10 +- 8 files changed, 1415 insertions(+), 1339 deletions(-) diff --git a/build/find_mac_sdk.py b/build/find_mac_sdk.py index 70b3771..6c8b0d3 100755 --- a/build/find_mac_sdk.py +++ b/build/find_mac_sdk.py @@ -16,148 +16,156 @@ def _AsVersion(version_str): - return tuple((int(s) for s in re.findall(r'(\d+)', version_str))) + return tuple((int(s) for s in re.findall(r'(\d+)', version_str))) def _RunXCRun(args, sdk=None): - xcrun_args = ['xcrun'] - if sdk is not None: - xcrun_args.extend(['--sdk', sdk]) - xcrun_args.extend(args) - return subprocess.check_output(xcrun_args).decode('utf-8').rstrip() + xcrun_args = ['xcrun'] + if sdk is not None: + xcrun_args.extend(['--sdk', sdk]) + xcrun_args.extend(args) + return subprocess.check_output(xcrun_args).decode('utf-8').rstrip() def _SDKPath(sdk=None): - return _RunXCRun(['--show-sdk-path'], sdk) + return _RunXCRun(['--show-sdk-path'], sdk) def _SDKVersion(sdk=None): - return _AsVersion(_RunXCRun(['--show-sdk-version'], sdk)) + return _AsVersion(_RunXCRun(['--show-sdk-version'], sdk)) class DidNotMeetCriteria(Exception): - pass + pass def _FindPlatformSDKWithMinimumVersion(platform, minimum_sdk_version_str): - minimum_sdk_version = _AsVersion(minimum_sdk_version_str) - - # Try the SDKs that Xcode knows about. - xcodebuild_showsdks_subprocess = subprocess.Popen( - ['xcodebuild', '-showsdks'], - stdout=subprocess.PIPE, - stderr=open(os.devnull, 'w')) - xcodebuild_showsdks_output = ( - xcodebuild_showsdks_subprocess.communicate()[0].decode('utf-8')) - if xcodebuild_showsdks_subprocess.returncode == 0: - # Collect strings instead of version objects to preserve the precise - # format used to identify each SDK. - sdk_version_strs = [] - for line in xcodebuild_showsdks_output.splitlines(): - match = re.match('[ \t].+[ \t]-sdk ' + re.escape(platform) + '(.+)$', - line) - if match: - sdk_version_str = match.group(1) - if _AsVersion(sdk_version_str) >= minimum_sdk_version: - sdk_version_strs.append(sdk_version_str) - - if len(sdk_version_strs) == 0: - raise DidNotMeetCriteria({'minimum': minimum_sdk_version_str, - 'platform': platform}) - sdk_version_str = sorted(sdk_version_strs, key=_AsVersion)[0] - sdk_path = _SDKPath(platform + sdk_version_str) - sdk_version = _AsVersion(sdk_version_str) - else: - # Xcode may not be installed. If the command-line tools are installed, use - # the system’s default SDK if it meets the requirements. - sdk_path = _SDKPath() - sdk_version = _SDKVersion() - if sdk_version < minimum_sdk_version: - raise DidNotMeetCriteria({'minimum': minimum_sdk_version_str, - 'platform': platform, - 'sdk_path': sdk_path, - 'sdk_version': str(sdk_version)}) - - return (sdk_version, sdk_path) + minimum_sdk_version = _AsVersion(minimum_sdk_version_str) + + # Try the SDKs that Xcode knows about. + xcodebuild_showsdks_subprocess = subprocess.Popen( + ['xcodebuild', '-showsdks'], + stdout=subprocess.PIPE, + stderr=open(os.devnull, 'w')) + xcodebuild_showsdks_output = ( + xcodebuild_showsdks_subprocess.communicate()[0].decode('utf-8')) + if xcodebuild_showsdks_subprocess.returncode == 0: + # Collect strings instead of version objects to preserve the precise + # format used to identify each SDK. + sdk_version_strs = [] + for line in xcodebuild_showsdks_output.splitlines(): + match = re.match( + '[ \t].+[ \t]-sdk ' + re.escape(platform) + '(.+)$', line) + if match: + sdk_version_str = match.group(1) + if _AsVersion(sdk_version_str) >= minimum_sdk_version: + sdk_version_strs.append(sdk_version_str) + + if len(sdk_version_strs) == 0: + raise DidNotMeetCriteria({ + 'minimum': minimum_sdk_version_str, + 'platform': platform + }) + sdk_version_str = sorted(sdk_version_strs, key=_AsVersion)[0] + sdk_path = _SDKPath(platform + sdk_version_str) + sdk_version = _AsVersion(sdk_version_str) + else: + # Xcode may not be installed. If the command-line tools are installed, + # use the system’s default SDK if it meets the requirements. + sdk_path = _SDKPath() + sdk_version = _SDKVersion() + if sdk_version < minimum_sdk_version: + raise DidNotMeetCriteria({ + 'minimum': minimum_sdk_version_str, + 'platform': platform, + 'sdk_path': sdk_path, + 'sdk_version': str(sdk_version) + }) + + return (sdk_version, sdk_path) def main(args): - parser = argparse.ArgumentParser( - description='Find an appropriate platform SDK', - epilog='Two lines will be written to standard output: the version of the ' - 'selected SDK, and its path.') - parser.add_argument('--developer-dir', - help='path to Xcode or Command Line Tools') - parser.add_argument('--exact', help='an exact SDK version to find') - parser.add_argument('--minimum', help='the minimum SDK version to find') - parser.add_argument('--path', help='a known SDK path to validate') - parser.add_argument('--platform', - default='macosx', - help='the platform to target') - parsed = parser.parse_args(args) - - if parsed.developer_dir is not None: - os.environ['DEVELOPER_DIR'] = parsed.developer_dir - - if (os.environ.get('DEVELOPER_DIR') is None and - subprocess.call(['xcode-select', '--print-path'], - stdout=open(os.devnull, 'w'), - stderr=open(os.devnull, 'w')) != 0): - # This is friendlier than letting the first invocation of xcrun or - # xcodebuild show the UI prompting to install developer tools at an - # inopportune time. - hint = 'Install Xcode and run "sudo xcodebuild -license"' - if parsed.platform == 'macosx': - hint += ', or install Command Line Tools with "xcode-select --install"' - hint += ('. If necessary, run "sudo xcode-select --switch" to select an ' - 'active developer tools installation.') - hint = '\n'.join(textwrap.wrap(hint, 80)) - print(os.path.basename(sys.argv[0]) + - ': No developer tools found.\n' + + parser = argparse.ArgumentParser( + description='Find an appropriate platform SDK', + epilog='Two lines will be written to standard output: the version of ' + 'the selected SDK, and its path.') + parser.add_argument('--developer-dir', + help='path to Xcode or Command Line Tools') + parser.add_argument('--exact', help='an exact SDK version to find') + parser.add_argument('--minimum', help='the minimum SDK version to find') + parser.add_argument('--path', help='a known SDK path to validate') + parser.add_argument('--platform', + default='macosx', + help='the platform to target') + parsed = parser.parse_args(args) + + if parsed.developer_dir is not None: + os.environ['DEVELOPER_DIR'] = parsed.developer_dir + + if (os.environ.get('DEVELOPER_DIR') is None and + subprocess.call(['xcode-select', '--print-path'], + stdout=open(os.devnull, 'w'), + stderr=open(os.devnull, 'w')) != 0): + # This is friendlier than letting the first invocation of xcrun or + # xcodebuild show the UI prompting to install developer tools at an + # inopportune time. + hint = 'Install Xcode and run "sudo xcodebuild -license"' + if parsed.platform == 'macosx': + hint += ( + ', or install Command Line Tools with "xcode-select --install"') + hint += ( + '. If necessary, run "sudo xcode-select --switch" to select an ' + 'active developer tools installation.') + hint = '\n'.join(textwrap.wrap(hint, 80)) + print(os.path.basename(sys.argv[0]) + ': No developer tools found.\n' + hint, - file=sys.stderr) - return 1 - - if parsed.path is not None: - # _SDKVersion() doesn’t work with a relative pathname argument or one that’s - # a symbolic link. Such paths are suitable for other purposes, like “clang - # -isysroot”, so use an absolute non-symbolic link path for _SDKVersion(), - # but preserve the user’s path in sdk_path. - sdk_version = _SDKVersion(os.path.realpath(parsed.path)) - sdk_path = parsed.path - elif parsed.exact is None and parsed.minimum is None: - # Use the platform’s default SDK. - sdk_version = _SDKVersion(parsed.platform) - sdk_path = _SDKPath(parsed.platform) - elif parsed.exact is not None: - sdk_version = _SDKVersion(parsed.platform + parsed.exact) - sdk_path = _SDKPath(parsed.platform + parsed.exact) - else: - (sdk_version, - sdk_path) = _FindPlatformSDKWithMinimumVersion(parsed.platform, - parsed.minimum) - - # These checks may be redundant depending on how the SDK was chosen. - if ((parsed.exact is not None and sdk_version != _AsVersion(parsed.exact)) or - (parsed.minimum is not None and - sdk_version < _AsVersion(parsed.minimum))): - raise DidNotMeetCriteria({'developer_dir': parsed.developer_dir, - 'exact': parsed.exact, - 'minimum': parsed.minimum, - 'path': parsed.path, - 'platform': parsed.platform, - 'sdk_path': sdk_path, - 'sdk_version': str(sdk_version)}) - - # Nobody wants trailing slashes. This is true even if “/” is the SDK: it’s - # better to return an empty string, which will be interpreted as “no sysroot.” - sdk_path = sdk_path.rstrip(os.path.sep) - - print(sdk_version) - print(sdk_path) - - return 0 + file=sys.stderr) + return 1 + + if parsed.path is not None: + # _SDKVersion() doesn’t work with a relative pathname argument or one + # that’s a symbolic link. Such paths are suitable for other purposes, + # like “clang -isysroot”, so use an absolute non-symbolic link path for + # _SDKVersion(), but preserve the user’s path in sdk_path. + sdk_version = _SDKVersion(os.path.realpath(parsed.path)) + sdk_path = parsed.path + elif parsed.exact is None and parsed.minimum is None: + # Use the platform’s default SDK. + sdk_version = _SDKVersion(parsed.platform) + sdk_path = _SDKPath(parsed.platform) + elif parsed.exact is not None: + sdk_version = _SDKVersion(parsed.platform + parsed.exact) + sdk_path = _SDKPath(parsed.platform + parsed.exact) + else: + (sdk_version, + sdk_path) = _FindPlatformSDKWithMinimumVersion(parsed.platform, + parsed.minimum) + + # These checks may be redundant depending on how the SDK was chosen. + if ((parsed.exact is not None and sdk_version != _AsVersion(parsed.exact)) + or (parsed.minimum is not None and + sdk_version < _AsVersion(parsed.minimum))): + raise DidNotMeetCriteria({ + 'developer_dir': parsed.developer_dir, + 'exact': parsed.exact, + 'minimum': parsed.minimum, + 'path': parsed.path, + 'platform': parsed.platform, + 'sdk_path': sdk_path, + 'sdk_version': str(sdk_version) + }) + + # Nobody wants trailing slashes. This is true even if “/” is the SDK: it’s + # better to return an empty string, which will be interpreted as “no + # sysroot.” + sdk_path = sdk_path.rstrip(os.path.sep) + + print(sdk_version) + print(sdk_path) + + return 0 if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) + sys.exit(main(sys.argv[1:])) diff --git a/build/ios/codesign.py b/build/ios/codesign.py index 9b539c3..03845d7 100644 --- a/build/ios/codesign.py +++ b/build/ios/codesign.py @@ -18,674 +18,707 @@ import tempfile if sys.version_info.major < 3: - basestring_compat = basestring + basestring_compat = basestring else: - basestring_compat = str + basestring_compat = str def GetProvisioningProfilesDir(): - """Returns the location of the installed mobile provisioning profiles. + """Returns the location of the installed mobile provisioning profiles. - Returns: - The path to the directory containing the installed mobile provisioning - profiles as a string. - """ - return os.path.join( - os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles') + Returns: + The path to the directory containing the installed mobile provisioning + profiles as a string. + """ + return os.path.join(os.environ['HOME'], 'Library', 'MobileDevice', + 'Provisioning Profiles') def ReadPlistFromString(plist_bytes): - """Parse property list from given |plist_bytes|. + """Parse property list from given |plist_bytes|. Args: - plist_bytes: contents of property list to load. Must be bytes in python 3. + plist_bytes: contents of property list to load. Must be bytes in python + 3. Returns: - The contents of property list as a python object. + The contents of property list as a python object. """ - if sys.version_info.major == 2: - return plistlib.readPlistFromString(plist_bytes) - else: - return plistlib.loads(plist_bytes) + if sys.version_info.major == 2: + return plistlib.readPlistFromString(plist_bytes) + else: + return plistlib.loads(plist_bytes) def LoadPlistFile(plist_path): - """Loads property list file at |plist_path|. - - Args: - plist_path: path to the property list file to load. - - Returns: - The content of the property list file as a python object. - """ - if sys.version_info.major == 2: - return plistlib.readPlistFromString( - subprocess.check_output( - ['xcrun', 'plutil', '-convert', 'xml1', '-o', '-', plist_path])) - else: - with open(plist_path, 'rb') as fp: - return plistlib.load(fp) - - -def CreateSymlink(value, location): - """Creates symlink with value at location if the target exists.""" - target = os.path.join(os.path.dirname(location), value) - if os.path.exists(location): - os.unlink(location) - os.symlink(value, location) - - -class Bundle(object): - """Wraps a bundle.""" - - def __init__(self, bundle_path, platform): - """Initializes the Bundle object with data from bundle Info.plist file.""" - self._path = bundle_path - self._kind = Bundle.Kind(platform, os.path.splitext(bundle_path)[-1]) - self._data = None - - def Load(self): - self._data = LoadPlistFile(self.info_plist_path) - - @staticmethod - def Kind(platform, extension): - if platform == 'iphonesimulator' or platform == 'iphoneos': - return 'ios' - if platform == 'macosx': - if extension == '.framework': - return 'mac_framework' - return 'mac' - raise ValueError('unknown bundle type %s for %s' % (extension, platform)) - - @property - def kind(self): - return self._kind - - @property - def path(self): - return self._path - - @property - def contents_dir(self): - if self._kind == 'mac': - return os.path.join(self.path, 'Contents') - if self._kind == 'mac_framework': - return os.path.join(self.path, 'Versions/A') - return self.path - - @property - def executable_dir(self): - if self._kind == 'mac': - return os.path.join(self.contents_dir, 'MacOS') - return self.contents_dir - - @property - def resources_dir(self): - if self._kind == 'mac' or self._kind == 'mac_framework': - return os.path.join(self.contents_dir, 'Resources') - return self.path - - @property - def info_plist_path(self): - if self._kind == 'mac_framework': - return os.path.join(self.resources_dir, 'Info.plist') - return os.path.join(self.contents_dir, 'Info.plist') - - @property - def signature_dir(self): - return os.path.join(self.contents_dir, '_CodeSignature') - - @property - def identifier(self): - return self._data['CFBundleIdentifier'] - - @property - def binary_name(self): - return self._data['CFBundleExecutable'] - - @property - def binary_path(self): - return os.path.join(self.executable_dir, self.binary_name) - - def Validate(self, expected_mappings): - """Checks that keys in the bundle have the expected value. + """Loads property list file at |plist_path|. Args: - expected_mappings: a dictionary of string to object, each mapping will - be looked up in the bundle data to check it has the same value (missing - values will be ignored) + plist_path: path to the property list file to load. Returns: - A dictionary of the key with a different value between expected_mappings - and the content of the bundle (i.e. errors) so that caller can format the - error message. The dictionary will be empty if there are no errors. + The content of the property list file as a python object. """ - errors = {} - for key, expected_value in expected_mappings.items(): - if key in self._data: - value = self._data[key] - if value != expected_value: - errors[key] = (value, expected_value) - return errors - - -class ProvisioningProfile(object): - """Wraps a mobile provisioning profile file.""" - - def __init__(self, provisioning_profile_path): - """Initializes the ProvisioningProfile with data from profile file.""" - self._path = provisioning_profile_path - self._data = ReadPlistFromString( - subprocess.check_output([ - 'xcrun', 'security', 'cms', '-D', '-u', 'certUsageAnyCA', '-i', - provisioning_profile_path - ])) - - @property - def path(self): - return self._path - - @property - def team_identifier(self): - return self._data.get('TeamIdentifier', [''])[0] - - @property - def name(self): - return self._data.get('Name', '') - - @property - def application_identifier_pattern(self): - return self._data.get('Entitlements', {}).get('application-identifier', '') + if sys.version_info.major == 2: + return plistlib.readPlistFromString( + subprocess.check_output( + ['xcrun', 'plutil', '-convert', 'xml1', '-o', '-', plist_path])) + else: + with open(plist_path, 'rb') as fp: + return plistlib.load(fp) - @property - def application_identifier_prefix(self): - return self._data.get('ApplicationIdentifierPrefix', [''])[0] - @property - def entitlements(self): - return self._data.get('Entitlements', {}) - - @property - def expiration_date(self): - return self._data.get('ExpirationDate', datetime.datetime.now()) +def CreateSymlink(value, location): + """Creates symlink with value at location if the target exists.""" + target = os.path.join(os.path.dirname(location), value) + if os.path.exists(location): + os.unlink(location) + os.symlink(value, location) - def ValidToSignBundle(self, bundle_identifier): - """Checks whether the provisioning profile can sign bundle_identifier. - Args: - bundle_identifier: the identifier of the bundle that needs to be signed. +class Bundle(object): + """Wraps a bundle.""" + + def __init__(self, bundle_path, platform): + """Initializes the Bundle object with data from bundle Info.plist + file.""" + self._path = bundle_path + self._kind = Bundle.Kind(platform, os.path.splitext(bundle_path)[-1]) + self._data = None + + def Load(self): + self._data = LoadPlistFile(self.info_plist_path) + + @staticmethod + def Kind(platform, extension): + if platform == 'iphonesimulator' or platform == 'iphoneos': + return 'ios' + if platform == 'macosx': + if extension == '.framework': + return 'mac_framework' + return 'mac' + raise ValueError('unknown bundle type %s for %s' % + (extension, platform)) + + @property + def kind(self): + return self._kind + + @property + def path(self): + return self._path + + @property + def contents_dir(self): + if self._kind == 'mac': + return os.path.join(self.path, 'Contents') + if self._kind == 'mac_framework': + return os.path.join(self.path, 'Versions/A') + return self.path + + @property + def executable_dir(self): + if self._kind == 'mac': + return os.path.join(self.contents_dir, 'MacOS') + return self.contents_dir + + @property + def resources_dir(self): + if self._kind == 'mac' or self._kind == 'mac_framework': + return os.path.join(self.contents_dir, 'Resources') + return self.path + + @property + def info_plist_path(self): + if self._kind == 'mac_framework': + return os.path.join(self.resources_dir, 'Info.plist') + return os.path.join(self.contents_dir, 'Info.plist') + + @property + def signature_dir(self): + return os.path.join(self.contents_dir, '_CodeSignature') + + @property + def identifier(self): + return self._data['CFBundleIdentifier'] + + @property + def binary_name(self): + return self._data['CFBundleExecutable'] + + @property + def binary_path(self): + return os.path.join(self.executable_dir, self.binary_name) + + def Validate(self, expected_mappings): + """Checks that keys in the bundle have the expected value. + + Args: + expected_mappings: a dictionary of string to object, each mapping + will be looked up in the bundle data to check it has the same value + (missing values will be ignored) + + Returns: + A dictionary of the key with a different value between + expected_mappings and the content of the bundle (i.e. errors) so + that caller can format the error message. The dictionary will be + empty if there are no errors. + """ + errors = {} + for key, expected_value in expected_mappings.items(): + if key in self._data: + value = self._data[key] + if value != expected_value: + errors[key] = (value, expected_value) + return errors - Returns: - True if the mobile provisioning profile can be used to sign a bundle - with the corresponding bundle_identifier, False otherwise. - """ - return fnmatch.fnmatch( - '%s.%s' % (self.application_identifier_prefix, bundle_identifier), - self.application_identifier_pattern) - def Install(self, installation_path): - """Copies mobile provisioning profile info to |installation_path|.""" - shutil.copy2(self.path, installation_path) +class ProvisioningProfile(object): + """Wraps a mobile provisioning profile file.""" + + def __init__(self, provisioning_profile_path): + """Initializes the ProvisioningProfile with data from profile file.""" + self._path = provisioning_profile_path + self._data = ReadPlistFromString( + subprocess.check_output([ + 'xcrun', 'security', 'cms', '-D', '-u', 'certUsageAnyCA', '-i', + provisioning_profile_path + ])) + + @property + def path(self): + return self._path + + @property + def team_identifier(self): + return self._data.get('TeamIdentifier', [''])[0] + + @property + def name(self): + return self._data.get('Name', '') + + @property + def application_identifier_pattern(self): + return self._data.get('Entitlements', {}).get('application-identifier', + '') + + @property + def application_identifier_prefix(self): + return self._data.get('ApplicationIdentifierPrefix', [''])[0] + + @property + def entitlements(self): + return self._data.get('Entitlements', {}) + + @property + def expiration_date(self): + return self._data.get('ExpirationDate', datetime.datetime.now()) + + def ValidToSignBundle(self, bundle_identifier): + """Checks whether the provisioning profile can sign bundle_identifier. + + Args: + bundle_identifier: the identifier of the bundle that needs to be + signed. + + Returns: + True if the mobile provisioning profile can be used to sign a bundle + with the corresponding bundle_identifier, False otherwise. + """ + return fnmatch.fnmatch( + '%s.%s' % (self.application_identifier_prefix, bundle_identifier), + self.application_identifier_pattern) + + def Install(self, installation_path): + """Copies mobile provisioning profile info to |installation_path|.""" + shutil.copy2(self.path, installation_path) class Entitlements(object): - """Wraps an Entitlement plist file.""" + """Wraps an Entitlement plist file.""" - def __init__(self, entitlements_path): - """Initializes Entitlements object from entitlement file.""" - self._path = entitlements_path - self._data = LoadPlistFile(self._path) + def __init__(self, entitlements_path): + """Initializes Entitlements object from entitlement file.""" + self._path = entitlements_path + self._data = LoadPlistFile(self._path) - @property - def path(self): - return self._path + @property + def path(self): + return self._path - def ExpandVariables(self, substitutions): - self._data = self._ExpandVariables(self._data, substitutions) + def ExpandVariables(self, substitutions): + self._data = self._ExpandVariables(self._data, substitutions) - def _ExpandVariables(self, data, substitutions): - if isinstance(data, basestring_compat): - for key, substitution in substitutions.items(): - data = data.replace('$(%s)' % (key,), substitution) - return data + def _ExpandVariables(self, data, substitutions): + if isinstance(data, basestring_compat): + for key, substitution in substitutions.items(): + data = data.replace('$(%s)' % (key,), substitution) + return data - if isinstance(data, dict): - for key, value in data.items(): - data[key] = self._ExpandVariables(value, substitutions) - return data + if isinstance(data, dict): + for key, value in data.items(): + data[key] = self._ExpandVariables(value, substitutions) + return data - if isinstance(data, list): - for i, value in enumerate(data): - data[i] = self._ExpandVariables(value, substitutions) + if isinstance(data, list): + for i, value in enumerate(data): + data[i] = self._ExpandVariables(value, substitutions) - return data + return data - def LoadDefaults(self, defaults): - for key, value in defaults.items(): - if key not in self._data: - self._data[key] = value + def LoadDefaults(self, defaults): + for key, value in defaults.items(): + if key not in self._data: + self._data[key] = value - def WriteTo(self, target_path): - with open(target_path, 'wb') as fp: - if sys.version_info.major == 2: - plistlib.writePlist(self._data, fp) - else: - plistlib.dump(self._data, fp) + def WriteTo(self, target_path): + with open(target_path, 'wb') as fp: + if sys.version_info.major == 2: + plistlib.writePlist(self._data, fp) + else: + plistlib.dump(self._data, fp) def FindProvisioningProfile(bundle_identifier, required): - """Finds mobile provisioning profile to use to sign bundle. - - Args: - bundle_identifier: the identifier of the bundle to sign. - - Returns: - The ProvisioningProfile object that can be used to sign the Bundle - object or None if no matching provisioning profile was found. - """ - provisioning_profile_paths = glob.glob( - os.path.join(GetProvisioningProfilesDir(), '*.mobileprovision')) - - # Iterate over all installed mobile provisioning profiles and filter those - # that can be used to sign the bundle, ignoring expired ones. - now = datetime.datetime.now() - valid_provisioning_profiles = [] - one_hour = datetime.timedelta(0, 3600) - for provisioning_profile_path in provisioning_profile_paths: - provisioning_profile = ProvisioningProfile(provisioning_profile_path) - if provisioning_profile.expiration_date - now < one_hour: - sys.stderr.write( - 'Warning: ignoring expired provisioning profile: %s.\n' % - provisioning_profile_path) - continue - if provisioning_profile.ValidToSignBundle(bundle_identifier): - valid_provisioning_profiles.append(provisioning_profile) - - if not valid_provisioning_profiles: - if required: - sys.stderr.write( - 'Error: no mobile provisioning profile found for "%s".\n' % - bundle_identifier) - sys.exit(1) - return None - - # Select the most specific mobile provisioning profile, i.e. the one with - # the longest application identifier pattern (prefer the one with the latest - # expiration date as a secondary criteria). - selected_provisioning_profile = max( - valid_provisioning_profiles, - key=lambda p: (len(p.application_identifier_pattern), p.expiration_date)) - - one_week = datetime.timedelta(7) - if selected_provisioning_profile.expiration_date - now < 2 * one_week: - sys.stderr.write( - 'Warning: selected provisioning profile will expire soon: %s' % - selected_provisioning_profile.path) - return selected_provisioning_profile + """Finds mobile provisioning profile to use to sign bundle. + + Args: + bundle_identifier: the identifier of the bundle to sign. + + Returns: + The ProvisioningProfile object that can be used to sign the Bundle + object or None if no matching provisioning profile was found. + """ + provisioning_profile_paths = glob.glob( + os.path.join(GetProvisioningProfilesDir(), '*.mobileprovision')) + + # Iterate over all installed mobile provisioning profiles and filter those + # that can be used to sign the bundle, ignoring expired ones. + now = datetime.datetime.now() + valid_provisioning_profiles = [] + one_hour = datetime.timedelta(0, 3600) + for provisioning_profile_path in provisioning_profile_paths: + provisioning_profile = ProvisioningProfile(provisioning_profile_path) + if provisioning_profile.expiration_date - now < one_hour: + sys.stderr.write( + 'Warning: ignoring expired provisioning profile: %s.\n' % + provisioning_profile_path) + continue + if provisioning_profile.ValidToSignBundle(bundle_identifier): + valid_provisioning_profiles.append(provisioning_profile) + + if not valid_provisioning_profiles: + if required: + sys.stderr.write( + 'Error: no mobile provisioning profile found for "%s".\n' % + bundle_identifier) + sys.exit(1) + return None + + # Select the most specific mobile provisioning profile, i.e. the one with + # the longest application identifier pattern (prefer the one with the latest + # expiration date as a secondary criteria). + selected_provisioning_profile = max( + valid_provisioning_profiles, + key=lambda p: + (len(p.application_identifier_pattern), p.expiration_date)) + + one_week = datetime.timedelta(7) + if selected_provisioning_profile.expiration_date - now < 2 * one_week: + sys.stderr.write( + 'Warning: selected provisioning profile will expire soon: %s' % + selected_provisioning_profile.path) + return selected_provisioning_profile def CodeSignBundle(bundle_path, identity, extra_args): - process = subprocess.Popen( - ['xcrun', 'codesign', '--force', '--sign', identity, '--timestamp=none'] + - list(extra_args) + [bundle_path], - stderr=subprocess.PIPE, - universal_newlines=True) - _, stderr = process.communicate() - if process.returncode: - sys.stderr.write(stderr) - sys.exit(process.returncode) - for line in stderr.splitlines(): - if line.endswith(': replacing existing signature'): - # Ignore warning about replacing existing signature as this should only - # happen when re-signing system frameworks (and then it is expected). - continue - sys.stderr.write(line) - sys.stderr.write('\n') + process = subprocess.Popen([ + 'xcrun', 'codesign', '--force', '--sign', identity, '--timestamp=none' + ] + list(extra_args) + [bundle_path], + stderr=subprocess.PIPE, + universal_newlines=True) + _, stderr = process.communicate() + if process.returncode: + sys.stderr.write(stderr) + sys.exit(process.returncode) + for line in stderr.splitlines(): + if line.endswith(': replacing existing signature'): + # Ignore warning about replacing existing signature as this should only + # happen when re-signing system frameworks (and then it is expected). + continue + sys.stderr.write(line) + sys.stderr.write('\n') def InstallSystemFramework(framework_path, bundle_path, args): - """Install framework from |framework_path| to |bundle| and code-re-sign it.""" - installed_framework_path = os.path.join( - bundle_path, 'Frameworks', os.path.basename(framework_path)) + """Install framework from |framework_path| to |bundle| and code-re-sign + it.""" + installed_framework_path = os.path.join(bundle_path, 'Frameworks', + os.path.basename(framework_path)) - if os.path.isfile(framework_path): - shutil.copy(framework_path, installed_framework_path) - elif os.path.isdir(framework_path): - if os.path.exists(installed_framework_path): - shutil.rmtree(installed_framework_path) - shutil.copytree(framework_path, installed_framework_path) + if os.path.isfile(framework_path): + shutil.copy(framework_path, installed_framework_path) + elif os.path.isdir(framework_path): + if os.path.exists(installed_framework_path): + shutil.rmtree(installed_framework_path) + shutil.copytree(framework_path, installed_framework_path) - CodeSignBundle(installed_framework_path, args.identity, - ['--deep', '--preserve-metadata=identifier,entitlements,flags']) + CodeSignBundle( + installed_framework_path, args.identity, + ['--deep', '--preserve-metadata=identifier,entitlements,flags']) def GenerateEntitlements(path, provisioning_profile, bundle_identifier): - """Generates an entitlements file. - - Args: - path: path to the entitlements template file - provisioning_profile: ProvisioningProfile object to use, may be None - bundle_identifier: identifier of the bundle to sign. - """ - entitlements = Entitlements(path) - if provisioning_profile: - entitlements.LoadDefaults(provisioning_profile.entitlements) - app_identifier_prefix = \ - provisioning_profile.application_identifier_prefix + '.' - else: - app_identifier_prefix = '*.' - entitlements.ExpandVariables({ - 'CFBundleIdentifier': bundle_identifier, - 'AppIdentifierPrefix': app_identifier_prefix, - }) - return entitlements + """Generates an entitlements file. + + Args: + path: path to the entitlements template file + provisioning_profile: ProvisioningProfile object to use, may be None + bundle_identifier: identifier of the bundle to sign. + """ + entitlements = Entitlements(path) + if provisioning_profile: + entitlements.LoadDefaults(provisioning_profile.entitlements) + app_identifier_prefix = \ + provisioning_profile.application_identifier_prefix + '.' + else: + app_identifier_prefix = '*.' + entitlements.ExpandVariables({ + 'CFBundleIdentifier': bundle_identifier, + 'AppIdentifierPrefix': app_identifier_prefix, + }) + return entitlements def GenerateBundleInfoPlist(bundle, plist_compiler, partial_plist): - """Generates the bundle Info.plist for a list of partial .plist files. - - Args: - bundle: a Bundle instance - plist_compiler: string, path to the Info.plist compiler - partial_plist: list of path to partial .plist files to merge - """ - - # Filter empty partial .plist files (this happens if an application - # does not compile any asset catalog, in which case the partial .plist - # file from the asset catalog compilation step is just a stamp file). - filtered_partial_plist = [] - for plist in partial_plist: - plist_size = os.stat(plist).st_size - if plist_size: - filtered_partial_plist.append(plist) - - # Invoke the plist_compiler script. It needs to be a python script. - subprocess.check_call([ - 'python3', - plist_compiler, - 'merge', - '-f', - 'binary1', - '-o', - bundle.info_plist_path, - ] + filtered_partial_plist) + """Generates the bundle Info.plist for a list of partial .plist files. + + Args: + bundle: a Bundle instance + plist_compiler: string, path to the Info.plist compiler + partial_plist: list of path to partial .plist files to merge + """ + + # Filter empty partial .plist files (this happens if an application + # does not compile any asset catalog, in which case the partial .plist + # file from the asset catalog compilation step is just a stamp file). + filtered_partial_plist = [] + for plist in partial_plist: + plist_size = os.stat(plist).st_size + if plist_size: + filtered_partial_plist.append(plist) + + # Invoke the plist_compiler script. It needs to be a python script. + subprocess.check_call([ + 'python3', + plist_compiler, + 'merge', + '-f', + 'binary1', + '-o', + bundle.info_plist_path, + ] + filtered_partial_plist) class Action(object): - """Class implementing one action supported by the script.""" + """Class implementing one action supported by the script.""" - @classmethod - def Register(cls, subparsers): - parser = subparsers.add_parser(cls.name, help=cls.help) - parser.set_defaults(func=cls._Execute) - cls._Register(parser) + @classmethod + def Register(cls, subparsers): + parser = subparsers.add_parser(cls.name, help=cls.help) + parser.set_defaults(func=cls._Execute) + cls._Register(parser) class CodeSignBundleAction(Action): - """Class implementing the code-sign-bundle action.""" - - name = 'code-sign-bundle' - help = 'perform code signature for a bundle' - - @staticmethod - def _Register(parser): - parser.add_argument( - '--entitlements', '-e', dest='entitlements_path', - help='path to the entitlements file to use') - parser.add_argument( - 'path', help='path to the iOS bundle to codesign') - parser.add_argument( - '--identity', '-i', required=True, - help='identity to use to codesign') - parser.add_argument( - '--binary', '-b', required=True, - help='path to the iOS bundle binary') - parser.add_argument( - '--framework', '-F', action='append', default=[], dest='frameworks', - help='install and resign system framework') - parser.add_argument( - '--disable-code-signature', action='store_true', dest='no_signature', - help='disable code signature') - parser.add_argument( - '--disable-embedded-mobileprovision', action='store_false', - default=True, dest='embedded_mobileprovision', - help='disable finding and embedding mobileprovision') - parser.add_argument( - '--platform', '-t', required=True, - help='platform the signed bundle is targeting') - parser.add_argument( - '--partial-info-plist', '-p', action='append', default=[], - help='path to partial Info.plist to merge to create bundle Info.plist') - parser.add_argument( - '--plist-compiler-path', '-P', action='store', - help='path to the plist compiler script (for --partial-info-plist)') - parser.set_defaults(no_signature=False) - - @staticmethod - def _Execute(args): - if not args.identity: - args.identity = '-' - - bundle = Bundle(args.path, args.platform) - - if args.partial_info_plist: - GenerateBundleInfoPlist(bundle, args.plist_compiler_path, - args.partial_info_plist) - - # The bundle Info.plist may have been updated by GenerateBundleInfoPlist() - # above. Load the bundle information from Info.plist after the modification - # have been written to disk. - bundle.Load() - - # According to Apple documentation, the application binary must be the same - # as the bundle name without the .app suffix. See crbug.com/740476 for more - # information on what problem this can cause. - # - # To prevent this class of error, fail with an error if the binary name is - # incorrect in the Info.plist as it is not possible to update the value in - # Info.plist at this point (the file has been copied by a different target - # and ninja would consider the build dirty if it was updated). - # - # Also checks that the name of the bundle is correct too (does not cause the - # build to be considered dirty, but still terminate the script in case of an - # incorrect bundle name). - # - # Apple documentation is available at: - # https://developer.apple.com/library/content/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html - bundle_name = os.path.splitext(os.path.basename(bundle.path))[0] - errors = bundle.Validate({ - 'CFBundleName': bundle_name, - 'CFBundleExecutable': bundle_name, - }) - if errors: - for key in sorted(errors): - value, expected_value = errors[key] - sys.stderr.write('%s: error: %s value incorrect: %s != %s\n' % ( - bundle.path, key, value, expected_value)) - sys.stderr.flush() - sys.exit(1) - - # Delete existing embedded mobile provisioning. - embedded_provisioning_profile = os.path.join( - bundle.path, 'embedded.mobileprovision') - if os.path.isfile(embedded_provisioning_profile): - os.unlink(embedded_provisioning_profile) - - # Delete existing code signature. - if os.path.exists(bundle.signature_dir): - shutil.rmtree(bundle.signature_dir) - - # Install system frameworks if requested. - for framework_path in args.frameworks: - InstallSystemFramework(framework_path, args.path, args) - - # Copy main binary into bundle. - if not os.path.isdir(bundle.executable_dir): - os.makedirs(bundle.executable_dir) - shutil.copy(args.binary, bundle.binary_path) - - if bundle.kind == 'mac_framework': - # Create Versions/Current -> Versions/A symlink - CreateSymlink('A', os.path.join(bundle.path, 'Versions/Current')) - - # Create $binary_name -> Versions/Current/$binary_name symlink - CreateSymlink(os.path.join('Versions/Current', bundle.binary_name), - os.path.join(bundle.path, bundle.binary_name)) - - # Create optional symlinks. - for name in ('Headers', 'Resources', 'Modules'): - target = os.path.join(bundle.path, 'Versions/A', name) - if os.path.exists(target): - CreateSymlink(os.path.join('Versions/Current', name), - os.path.join(bundle.path, name)) - else: - obsolete_path = os.path.join(bundle.path, name) - if os.path.exists(obsolete_path): - os.unlink(obsolete_path) - - if args.no_signature: - return - - codesign_extra_args = [] - - if args.embedded_mobileprovision: - # Find mobile provisioning profile and embeds it into the bundle (if a - # code signing identify has been provided, fails if no valid mobile - # provisioning is found). - provisioning_profile_required = args.identity != '-' - provisioning_profile = FindProvisioningProfile( - bundle.identifier, provisioning_profile_required) - if provisioning_profile and args.platform != 'iphonesimulator': - provisioning_profile.Install(embedded_provisioning_profile) - - if args.entitlements_path is not None: - temporary_entitlements_file = \ - tempfile.NamedTemporaryFile(suffix='.xcent') - codesign_extra_args.extend( - ['--entitlements', temporary_entitlements_file.name]) - - entitlements = GenerateEntitlements( - args.entitlements_path, provisioning_profile, bundle.identifier) - entitlements.WriteTo(temporary_entitlements_file.name) - - CodeSignBundle(bundle.path, args.identity, codesign_extra_args) + """Class implementing the code-sign-bundle action.""" + + name = 'code-sign-bundle' + help = 'perform code signature for a bundle' + + @staticmethod + def _Register(parser): + parser.add_argument('--entitlements', + '-e', + dest='entitlements_path', + help='path to the entitlements file to use') + parser.add_argument('path', help='path to the iOS bundle to codesign') + parser.add_argument('--identity', + '-i', + required=True, + help='identity to use to codesign') + parser.add_argument('--binary', + '-b', + required=True, + help='path to the iOS bundle binary') + parser.add_argument('--framework', + '-F', + action='append', + default=[], + dest='frameworks', + help='install and resign system framework') + parser.add_argument('--disable-code-signature', + action='store_true', + dest='no_signature', + help='disable code signature') + parser.add_argument( + '--disable-embedded-mobileprovision', + action='store_false', + default=True, + dest='embedded_mobileprovision', + help='disable finding and embedding mobileprovision') + parser.add_argument('--platform', + '-t', + required=True, + help='platform the signed bundle is targeting') + parser.add_argument( + '--partial-info-plist', + '-p', + action='append', + default=[], + help= + 'path to partial Info.plist to merge to create bundle Info.plist') + parser.add_argument( + '--plist-compiler-path', + '-P', + action='store', + help='path to the plist compiler script (for --partial-info-plist)') + parser.set_defaults(no_signature=False) + + @staticmethod + def _Execute(args): + if not args.identity: + args.identity = '-' + + bundle = Bundle(args.path, args.platform) + + if args.partial_info_plist: + GenerateBundleInfoPlist(bundle, args.plist_compiler_path, + args.partial_info_plist) + + # The bundle Info.plist may have been updated by + # GenerateBundleInfoPlist() above. Load the bundle information from + # Info.plist after the modification have been written to disk. + bundle.Load() + + # According to Apple documentation, the application binary must be the + # same as the bundle name without the .app suffix. See crbug.com/740476 + # for more information on what problem this can cause. + # + # To prevent this class of error, fail with an error if the binary name + # is incorrect in the Info.plist as it is not possible to update the + # value in Info.plist at this point (the file has been copied by a + # different target and ninja would consider the build dirty if it was + # updated). + # + # Also checks that the name of the bundle is correct too (does not cause + # the build to be considered dirty, but still terminate the script in + # case of an incorrect bundle name). + # + # Apple documentation is available at: + # https://developer.apple.com/library/content/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html + bundle_name = os.path.splitext(os.path.basename(bundle.path))[0] + errors = bundle.Validate({ + 'CFBundleName': bundle_name, + 'CFBundleExecutable': bundle_name, + }) + if errors: + for key in sorted(errors): + value, expected_value = errors[key] + sys.stderr.write('%s: error: %s value incorrect: %s != %s\n' % + (bundle.path, key, value, expected_value)) + sys.stderr.flush() + sys.exit(1) + + # Delete existing embedded mobile provisioning. + embedded_provisioning_profile = os.path.join( + bundle.path, 'embedded.mobileprovision') + if os.path.isfile(embedded_provisioning_profile): + os.unlink(embedded_provisioning_profile) + + # Delete existing code signature. + if os.path.exists(bundle.signature_dir): + shutil.rmtree(bundle.signature_dir) + + # Install system frameworks if requested. + for framework_path in args.frameworks: + InstallSystemFramework(framework_path, args.path, args) + + # Copy main binary into bundle. + if not os.path.isdir(bundle.executable_dir): + os.makedirs(bundle.executable_dir) + shutil.copy(args.binary, bundle.binary_path) + + if bundle.kind == 'mac_framework': + # Create Versions/Current -> Versions/A symlink + CreateSymlink('A', os.path.join(bundle.path, 'Versions/Current')) + + # Create $binary_name -> Versions/Current/$binary_name symlink + CreateSymlink(os.path.join('Versions/Current', bundle.binary_name), + os.path.join(bundle.path, bundle.binary_name)) + + # Create optional symlinks. + for name in ('Headers', 'Resources', 'Modules'): + target = os.path.join(bundle.path, 'Versions/A', name) + if os.path.exists(target): + CreateSymlink(os.path.join('Versions/Current', name), + os.path.join(bundle.path, name)) + else: + obsolete_path = os.path.join(bundle.path, name) + if os.path.exists(obsolete_path): + os.unlink(obsolete_path) + + if args.no_signature: + return + + codesign_extra_args = [] + + if args.embedded_mobileprovision: + # Find mobile provisioning profile and embeds it into the bundle (if + # a code signing identify has been provided, fails if no valid + # mobile provisioning is found). + provisioning_profile_required = args.identity != '-' + provisioning_profile = FindProvisioningProfile( + bundle.identifier, provisioning_profile_required) + if provisioning_profile and args.platform != 'iphonesimulator': + provisioning_profile.Install(embedded_provisioning_profile) + + if args.entitlements_path is not None: + temporary_entitlements_file = \ + tempfile.NamedTemporaryFile(suffix='.xcent') + codesign_extra_args.extend( + ['--entitlements', temporary_entitlements_file.name]) + + entitlements = GenerateEntitlements(args.entitlements_path, + provisioning_profile, + bundle.identifier) + entitlements.WriteTo(temporary_entitlements_file.name) + + CodeSignBundle(bundle.path, args.identity, codesign_extra_args) class CodeSignFileAction(Action): - """Class implementing code signature for a single file.""" - - name = 'code-sign-file' - help = 'code-sign a single file' - - @staticmethod - def _Register(parser): - parser.add_argument( - 'path', help='path to the file to codesign') - parser.add_argument( - '--identity', '-i', required=True, - help='identity to use to codesign') - parser.add_argument( - '--output', '-o', - help='if specified copy the file to that location before signing it') - parser.set_defaults(sign=True) - - @staticmethod - def _Execute(args): - if not args.identity: - args.identity = '-' - - install_path = args.path - if args.output: - - if os.path.isfile(args.output): - os.unlink(args.output) - elif os.path.isdir(args.output): - shutil.rmtree(args.output) - - if os.path.isfile(args.path): - shutil.copy(args.path, args.output) - elif os.path.isdir(args.path): - shutil.copytree(args.path, args.output) - - install_path = args.output - - CodeSignBundle(install_path, args.identity, - ['--deep', '--preserve-metadata=identifier,entitlements']) + """Class implementing code signature for a single file.""" + + name = 'code-sign-file' + help = 'code-sign a single file' + + @staticmethod + def _Register(parser): + parser.add_argument('path', help='path to the file to codesign') + parser.add_argument('--identity', + '-i', + required=True, + help='identity to use to codesign') + parser.add_argument( + '--output', + '-o', + help='if specified copy the file to that location before signing it' + ) + parser.set_defaults(sign=True) + + @staticmethod + def _Execute(args): + if not args.identity: + args.identity = '-' + + install_path = args.path + if args.output: + + if os.path.isfile(args.output): + os.unlink(args.output) + elif os.path.isdir(args.output): + shutil.rmtree(args.output) + + if os.path.isfile(args.path): + shutil.copy(args.path, args.output) + elif os.path.isdir(args.path): + shutil.copytree(args.path, args.output) + + install_path = args.output + + CodeSignBundle( + install_path, args.identity, + ['--deep', '--preserve-metadata=identifier,entitlements']) class GenerateEntitlementsAction(Action): - """Class implementing the generate-entitlements action.""" - - name = 'generate-entitlements' - help = 'generate entitlements file' - - @staticmethod - def _Register(parser): - parser.add_argument( - '--entitlements', '-e', dest='entitlements_path', - help='path to the entitlements file to use') - parser.add_argument( - 'path', help='path to the entitlements file to generate') - parser.add_argument( - '--info-plist', '-p', required=True, - help='path to the bundle Info.plist') - - @staticmethod - def _Execute(args): - info_plist = LoadPlistFile(args.info_plist) - bundle_identifier = info_plist['CFBundleIdentifier'] - provisioning_profile = FindProvisioningProfile(bundle_identifier, False) - entitlements = GenerateEntitlements( - args.entitlements_path, provisioning_profile, bundle_identifier) - entitlements.WriteTo(args.path) + """Class implementing the generate-entitlements action.""" + + name = 'generate-entitlements' + help = 'generate entitlements file' + + @staticmethod + def _Register(parser): + parser.add_argument('--entitlements', + '-e', + dest='entitlements_path', + help='path to the entitlements file to use') + parser.add_argument('path', + help='path to the entitlements file to generate') + parser.add_argument('--info-plist', + '-p', + required=True, + help='path to the bundle Info.plist') + + @staticmethod + def _Execute(args): + info_plist = LoadPlistFile(args.info_plist) + bundle_identifier = info_plist['CFBundleIdentifier'] + provisioning_profile = FindProvisioningProfile(bundle_identifier, False) + entitlements = GenerateEntitlements(args.entitlements_path, + provisioning_profile, + bundle_identifier) + entitlements.WriteTo(args.path) class FindProvisioningProfileAction(Action): - """Class implementing the find-codesign-identity action.""" - - name = 'find-provisioning-profile' - help = 'find provisioning profile for use by Xcode project generator' - - @staticmethod - def _Register(parser): - parser.add_argument('--bundle-id', - '-b', - required=True, - help='bundle identifier') - - @staticmethod - def _Execute(args): - provisioning_profile_info = {} - provisioning_profile = FindProvisioningProfile(args.bundle_id, False) - for key in ('team_identifier', 'name'): - if provisioning_profile: - provisioning_profile_info[key] = getattr(provisioning_profile, key) - else: - provisioning_profile_info[key] = '' - print(json.dumps(provisioning_profile_info)) + """Class implementing the find-codesign-identity action.""" + + name = 'find-provisioning-profile' + help = 'find provisioning profile for use by Xcode project generator' + + @staticmethod + def _Register(parser): + parser.add_argument('--bundle-id', + '-b', + required=True, + help='bundle identifier') + + @staticmethod + def _Execute(args): + provisioning_profile_info = {} + provisioning_profile = FindProvisioningProfile(args.bundle_id, False) + for key in ('team_identifier', 'name'): + if provisioning_profile: + provisioning_profile_info[key] = getattr( + provisioning_profile, key) + else: + provisioning_profile_info[key] = '' + print(json.dumps(provisioning_profile_info)) def Main(): - # Cache this codec so that plistlib can find it. See - # https://crbug.com/999461#c12 for more details. - codecs.lookup('utf-8') + # Cache this codec so that plistlib can find it. See + # https://crbug.com/999461#c12 for more details. + codecs.lookup('utf-8') - parser = argparse.ArgumentParser('codesign iOS bundles') - subparsers = parser.add_subparsers() + parser = argparse.ArgumentParser('codesign iOS bundles') + subparsers = parser.add_subparsers() - actions = [ - CodeSignBundleAction, - CodeSignFileAction, - GenerateEntitlementsAction, - FindProvisioningProfileAction, - ] + actions = [ + CodeSignBundleAction, + CodeSignFileAction, + GenerateEntitlementsAction, + FindProvisioningProfileAction, + ] - for action in actions: - action.Register(subparsers) + for action in actions: + action.Register(subparsers) - args = parser.parse_args() - args.func(args) + args = parser.parse_args() + args.func(args) if __name__ == '__main__': - sys.exit(Main()) + sys.exit(Main()) diff --git a/build/ios/find_signing_identity.py b/build/ios/find_signing_identity.py index d6ef368..d4e734a 100644 --- a/build/ios/find_signing_identity.py +++ b/build/ios/find_signing_identity.py @@ -12,78 +12,81 @@ def Redact(value, from_nth_char=5): - """Redact value past the N-th character.""" - return value[:from_nth_char] + '*' * (len(value) - from_nth_char) + """Redact value past the N-th character.""" + return value[:from_nth_char] + '*' * (len(value) - from_nth_char) class Identity(object): - """Represents a valid identity.""" + """Represents a valid identity.""" - def __init__(self, identifier, name, team): - self.identifier = identifier - self.name = name - self.team = team + def __init__(self, identifier, name, team): + self.identifier = identifier + self.name = name + self.team = team - def redacted(self): - return Identity(Redact(self.identifier), self.name, Redact(self.team)) + def redacted(self): + return Identity(Redact(self.identifier), self.name, Redact(self.team)) - def format(self): - return '%s: "%s (%s)"' % (self.identifier, self.name, self.team) + def format(self): + return '%s: "%s (%s)"' % (self.identifier, self.name, self.team) def ListIdentities(): - return subprocess.check_output([ - 'xcrun', - 'security', - 'find-identity', - '-v', - '-p', - 'codesigning', - ]).decode('utf8') + return subprocess.check_output([ + 'xcrun', + 'security', + 'find-identity', + '-v', + '-p', + 'codesigning', + ]).decode('utf8') def FindValidIdentity(pattern): - """Find all identities matching the pattern.""" - lines = list(l.strip() for l in ListIdentities().splitlines()) - # Look for something like "2) XYZ "iPhone Developer: Name (ABC)"" - regex = re.compile('[0-9]+\) ([A-F0-9]+) "([^"(]*) \(([^)"]*)\)"') + """Find all identities matching the pattern.""" + lines = list(l.strip() for l in ListIdentities().splitlines()) + # Look for something like "2) XYZ "iPhone Developer: Name (ABC)"" + regex = re.compile('[0-9]+\) ([A-F0-9]+) "([^"(]*) \(([^)"]*)\)"') - result = [] - for line in lines: - res = regex.match(line) - if res is None: - continue - if pattern is None or pattern in res.group(2): - result.append(Identity(*res.groups())) - return result + result = [] + for line in lines: + res = regex.match(line) + if res is None: + continue + if pattern is None or pattern in res.group(2): + result.append(Identity(*res.groups())) + return result def Main(args): - parser = argparse.ArgumentParser('codesign iOS bundles') - parser.add_argument( - '--identity-description', required=True, dest='pattern', - help='Text description used to select the code signing identity.') - parsed = parser.parse_args(args) - - identities = FindValidIdentity(parsed.pattern) - if len(identities) == 1: - print(identities[0].identifier, end='') - return 0 - - all_identities = FindValidIdentity(None) - - print('Automatic code signing identity selection was enabled but could not') - print('find exactly one codesigning identity matching "%s".' % parsed.pattern) - print('') - print('Check that the keychain is accessible and that there is exactly one') - print('valid codesigning identity matching the pattern. Here is the parsed') - print('output of `xcrun security find-identity -v -p codesigning`:') - print() - for i, identity in enumerate(all_identities): - print(' %d) %s' % (i + 1, identity.redacted().format())) - print(' %d valid identities found' % (len(all_identities))) - return 1 + parser = argparse.ArgumentParser('codesign iOS bundles') + parser.add_argument( + '--identity-description', + required=True, + dest='pattern', + help='Text description used to select the code signing identity.') + parsed = parser.parse_args(args) + + identities = FindValidIdentity(parsed.pattern) + if len(identities) == 1: + print(identities[0].identifier, end='') + return 0 + + all_identities = FindValidIdentity(None) + + print('Automatic code signing identity selection was enabled but could not') + print('find exactly one codesigning identity matching "%s".' % + parsed.pattern) + print('') + print('Check that the keychain is accessible and that there is exactly one') + print('valid codesigning identity matching the pattern. Here is the parsed') + print('output of `xcrun security find-identity -v -p codesigning`:') + print() + for i, identity in enumerate(all_identities): + print(' %d) %s' % (i + 1, identity.redacted().format())) + print(' %d valid identities found' % (len(all_identities))) + return 1 if __name__ == '__main__': - sys.exit(Main(sys.argv[1:])) + sys.exit(Main(sys.argv[1:])) diff --git a/build/ios/plist_util.py b/build/ios/plist_util.py index fb480a2..7873a78 100644 --- a/build/ios/plist_util.py +++ b/build/ios/plist_util.py @@ -10,19 +10,18 @@ import subprocess import sys import tempfile -import shlex if sys.version_info.major < 3: - basestring_compat = basestring + basestring_compat = basestring else: - basestring_compat = str + basestring_compat = str # Xcode substitutes variables like ${PRODUCT_NAME} or $(PRODUCT_NAME) when -# compiling Info.plist. It also supports supports modifiers like :identifier -# or :rfc1034identifier. SUBSTITUTION_REGEXP_LIST is a list of regular -# expressions matching a variable substitution pattern with an optional -# modifier, while INVALID_CHARACTER_REGEXP matches all characters that are -# not valid in an "identifier" value (used when applying the modifier). +# compiling Info.plist. It also supports supports modifiers like :identifier or +# :rfc1034identifier. SUBSTITUTION_REGEXP_LIST is a list of regular expressions +# matching a variable substitution pattern with an optional modifier, while +# INVALID_CHARACTER_REGEXP matches all characters that are not valid in an +# "identifier" value (used when applying the modifier). INVALID_CHARACTER_REGEXP = re.compile(r'[_/\s]') SUBSTITUTION_REGEXP_LIST = ( re.compile(r'\$\{(?P[^}]*?)(?P:[^}]*)?\}'), @@ -31,235 +30,244 @@ class SubstitutionError(Exception): - def __init__(self, key): - super(SubstitutionError, self).__init__() - self.key = key - def __str__(self): - return "SubstitutionError: {}".format(self.key) + def __init__(self, key): + super(SubstitutionError, self).__init__() + self.key = key + def __str__(self): + return "SubstitutionError: {}".format(self.key) -def InterpolateString(value, substitutions): - """Interpolates variable references into |value| using |substitutions|. - - Inputs: - value: a string - substitutions: a mapping of variable names to values - - Returns: - A new string with all variables references ${VARIABLES} replaced by their - value in |substitutions|. Raises SubstitutionError if a variable has no - substitution. - """ - - def repl(match): - variable = match.group('id') - if variable not in substitutions: - raise SubstitutionError(variable) - # Some values need to be identifier and thus the variables references may - # contains :modifier attributes to indicate how they should be converted - # to identifiers ("identifier" replaces all invalid characters by '_' and - # "rfc1034identifier" replaces them by "-" to make valid URI too). - modifier = match.group('modifier') - if modifier == ':identifier': - return INVALID_CHARACTER_REGEXP.sub('_', substitutions[variable]) - elif modifier == ':rfc1034identifier': - return INVALID_CHARACTER_REGEXP.sub('-', substitutions[variable]) - else: - return substitutions[variable] - for substitution_regexp in SUBSTITUTION_REGEXP_LIST: - value = substitution_regexp.sub(repl, value) - return value +def InterpolateString(value, substitutions): + """Interpolates variable references into |value| using |substitutions|. + + Args: + value: a string + substitutions: a mapping of variable names to values + + Returns: + A new string with all variables references ${VARIABLES} replaced by + their value in |substitutions|. Raises SubstitutionError if a variable + has no substitution. + """ + + def repl(match): + variable = match.group('id') + if variable not in substitutions: + raise SubstitutionError(variable) + # Some values need to be identifier and thus the variables references + # may contains :modifier attributes to indicate how they should be + # converted to identifiers ("identifier" replaces all invalid characters + # by '_' and "rfc1034identifier" replaces them by "-" to make valid URI + # too). + modifier = match.group('modifier') + if modifier == ':identifier': + return INVALID_CHARACTER_REGEXP.sub('_', substitutions[variable]) + elif modifier == ':rfc1034identifier': + return INVALID_CHARACTER_REGEXP.sub('-', substitutions[variable]) + else: + return substitutions[variable] + + for substitution_regexp in SUBSTITUTION_REGEXP_LIST: + value = substitution_regexp.sub(repl, value) + return value def Interpolate(value, substitutions): - """Interpolates variable references into |value| using |substitutions|. - - Inputs: - value: a value, can be a dictionary, list, string or other - substitutions: a mapping of variable names to values - - Returns: - A new value with all variables references ${VARIABLES} replaced by their - value in |substitutions|. Raises SubstitutionError if a variable has no - substitution. - """ - if isinstance(value, dict): - return {k: Interpolate(v, substitutions) for k, v in value.items()} - if isinstance(value, list): - return [Interpolate(v, substitutions) for v in value] - if isinstance(value, basestring_compat): - return InterpolateString(value, substitutions) - return value + """Interpolates variable references into |value| using |substitutions|. + + Args: + value: a value, can be a dictionary, list, string or other + substitutions: a mapping of variable names to values + + Returns: + A new value with all variables references ${VARIABLES} replaced by their + value in |substitutions|. Raises SubstitutionError if a variable has no + substitution. + """ + if isinstance(value, dict): + return {k: Interpolate(v, substitutions) for k, v in value.items()} + if isinstance(value, list): + return [Interpolate(v, substitutions) for v in value] + if isinstance(value, basestring_compat): + return InterpolateString(value, substitutions) + return value def LoadPList(path): - """Loads Plist at |path| and returns it as a dictionary.""" - if sys.version_info.major == 2: - fd, name = tempfile.mkstemp() - try: - subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path]) - with os.fdopen(fd, 'rb') as f: - return plistlib.readPlist(f) - finally: - os.unlink(name) - else: - with open(path, 'rb') as f: - return plistlib.load(f) + """Loads Plist at |path| and returns it as a dictionary.""" + if sys.version_info.major == 2: + fd, name = tempfile.mkstemp() + try: + subprocess.check_call( + ['plutil', '-convert', 'xml1', '-o', name, path]) + with os.fdopen(fd, 'rb') as f: + return plistlib.readPlist(f) + finally: + os.unlink(name) + else: + with open(path, 'rb') as f: + return plistlib.load(f) def SavePList(path, format, data): - """Saves |data| as a Plist to |path| in the specified |format|.""" - # The below does not replace the destination file but update it in place, - # so if more than one hardlink points to destination all of them will be - # modified. This is not what is expected, so delete destination file if - # it does exist. - if os.path.exists(path): - os.unlink(path) - if sys.version_info.major == 2: - fd, name = tempfile.mkstemp() - try: - with os.fdopen(fd, 'wb') as f: - plistlib.writePlist(data, f) - subprocess.check_call(['plutil', '-convert', format, '-o', path, name]) - finally: - os.unlink(name) - else: - with open(path, 'wb') as f: - plist_format = {'binary1': plistlib.FMT_BINARY, 'xml1': plistlib.FMT_XML} - plistlib.dump(data, f, fmt=plist_format[format]) + """Saves |data| as a Plist to |path| in the specified |format|.""" + # The below does not replace the destination file but update it in place, + # so if more than one hardlink points to destination all of them will be + # modified. This is not what is expected, so delete destination file if + # it does exist. + if os.path.exists(path): + os.unlink(path) + if sys.version_info.major == 2: + fd, name = tempfile.mkstemp() + try: + with os.fdopen(fd, 'wb') as f: + plistlib.writePlist(data, f) + subprocess.check_call( + ['plutil', '-convert', format, '-o', path, name]) + finally: + os.unlink(name) + else: + with open(path, 'wb') as f: + plist_format = { + 'binary1': plistlib.FMT_BINARY, + 'xml1': plistlib.FMT_XML + } + plistlib.dump(data, f, fmt=plist_format[format]) def MergePList(plist1, plist2): - """Merges |plist1| with |plist2| recursively. - - Creates a new dictionary representing a Property List (.plist) files by - merging the two dictionary |plist1| and |plist2| recursively (only for - dictionary values). List value will be concatenated. - - Args: - plist1: a dictionary representing a Property List (.plist) file - plist2: a dictionary representing a Property List (.plist) file - - Returns: - A new dictionary representing a Property List (.plist) file by merging - |plist1| with |plist2|. If any value is a dictionary, they are merged - recursively, otherwise |plist2| value is used. If values are list, they - are concatenated. - """ - result = plist1.copy() - for key, value in plist2.items(): - if isinstance(value, dict): - old_value = result.get(key) - if isinstance(old_value, dict): - value = MergePList(old_value, value) - if isinstance(value, list): - value = plist1.get(key, []) + plist2.get(key, []) - result[key] = value - return result + """Merges |plist1| with |plist2| recursively. + + Creates a new dictionary representing a Property List (.plist) files by + merging the two dictionary |plist1| and |plist2| recursively (only for + dictionary values). List value will be concatenated. + + Args: + plist1: a dictionary representing a Property List (.plist) file plist2: + a dictionary representing a Property List (.plist) file + + Returns: + A new dictionary representing a Property List (.plist) file by merging + |plist1| with |plist2|. If any value is a dictionary, they are merged + recursively, otherwise |plist2| value is used. If values are list, they + are concatenated. + """ + result = plist1.copy() + for key, value in plist2.items(): + if isinstance(value, dict): + old_value = result.get(key) + if isinstance(old_value, dict): + value = MergePList(old_value, value) + if isinstance(value, list): + value = plist1.get(key, []) + plist2.get(key, []) + result[key] = value + return result class Action(object): - """Class implementing one action supported by the script.""" + """Class implementing one action supported by the script.""" - @classmethod - def Register(cls, subparsers): - parser = subparsers.add_parser(cls.name, help=cls.help) - parser.set_defaults(func=cls._Execute) - cls._Register(parser) + @classmethod + def Register(cls, subparsers): + parser = subparsers.add_parser(cls.name, help=cls.help) + parser.set_defaults(func=cls._Execute) + cls._Register(parser) class MergeAction(Action): - """Class to merge multiple plist files.""" - - name = 'merge' - help = 'merge multiple plist files' - - @staticmethod - def _Register(parser): - parser.add_argument('-o', - '--output', - required=True, - help='path to the output plist file') - parser.add_argument('-f', - '--format', - required=True, - choices=('xml1', 'binary1'), - help='format of the plist file to generate') - parser.add_argument( - '-x', - '--xcode-version', - help='version of Xcode, ignored (can be used to force rebuild)') - parser.add_argument('path', nargs="+", help='path to plist files to merge') - - @staticmethod - def _Execute(args): - data = {} - for filename in args.path: - data = MergePList(data, LoadPList(filename)) - SavePList(args.output, args.format, data) + """Class to merge multiple plist files.""" + + name = 'merge' + help = 'merge multiple plist files' + + @staticmethod + def _Register(parser): + parser.add_argument('-o', + '--output', + required=True, + help='path to the output plist file') + parser.add_argument('-f', + '--format', + required=True, + choices=('xml1', 'binary1'), + help='format of the plist file to generate') + parser.add_argument( + '-x', + '--xcode-version', + help='version of Xcode, ignored (can be used to force rebuild)') + parser.add_argument('path', + nargs="+", + help='path to plist files to merge') + + @staticmethod + def _Execute(args): + data = {} + for filename in args.path: + data = MergePList(data, LoadPList(filename)) + SavePList(args.output, args.format, data) class SubstituteAction(Action): - """Class implementing the variable substitution in a plist file.""" - - name = 'substitute' - help = 'perform pattern substitution in a plist file' - - @staticmethod - def _Register(parser): - parser.add_argument('-o', - '--output', - required=True, - help='path to the output plist file') - parser.add_argument('-t', - '--template', - required=True, - help='path to the template file') - parser.add_argument('-s', - '--substitution', - action='append', - default=[], - help='substitution rule in the format key=value') - parser.add_argument('-f', - '--format', - required=True, - choices=('xml1', 'binary1'), - help='format of the plist file to generate') - parser.add_argument( - '-x', - '--xcode-version', - help='version of Xcode, ignored (can be used to force rebuild)') - - @staticmethod - def _Execute(args): - substitutions = {} - for substitution in args.substitution: - key, value = substitution.split('=', 1) - substitutions[key] = value - data = Interpolate(LoadPList(args.template), substitutions) - SavePList(args.output, args.format, data) + """Class implementing the variable substitution in a plist file.""" + + name = 'substitute' + help = 'perform pattern substitution in a plist file' + + @staticmethod + def _Register(parser): + parser.add_argument('-o', + '--output', + required=True, + help='path to the output plist file') + parser.add_argument('-t', + '--template', + required=True, + help='path to the template file') + parser.add_argument('-s', + '--substitution', + action='append', + default=[], + help='substitution rule in the format key=value') + parser.add_argument('-f', + '--format', + required=True, + choices=('xml1', 'binary1'), + help='format of the plist file to generate') + parser.add_argument( + '-x', + '--xcode-version', + help='version of Xcode, ignored (can be used to force rebuild)') + + @staticmethod + def _Execute(args): + substitutions = {} + for substitution in args.substitution: + key, value = substitution.split('=', 1) + substitutions[key] = value + data = Interpolate(LoadPList(args.template), substitutions) + SavePList(args.output, args.format, data) def Main(): - # Cache this codec so that plistlib can find it. See - # https://crbug.com/1005190#c2 for more details. - codecs.lookup('utf-8') + # Cache this codec so that plistlib can find it. See + # https://crbug.com/1005190#c2 for more details. + codecs.lookup('utf-8') - parser = argparse.ArgumentParser(description='manipulate plist files') - subparsers = parser.add_subparsers() + parser = argparse.ArgumentParser(description='manipulate plist files') + subparsers = parser.add_subparsers() - for action in [MergeAction, SubstituteAction]: - action.Register(subparsers) + for action in [MergeAction, SubstituteAction]: + action.Register(subparsers) - args = parser.parse_args() - args.func(args) + args = parser.parse_args() + args.func(args) if __name__ == '__main__': - # TODO(https://crbug.com/941669): Temporary workaround until all scripts use - # python3 by default. - if sys.version_info[0] < 3: - os.execvp('python3', ['python3'] + sys.argv) - sys.exit(Main()) + # TODO(https://crbug.com/941669): Temporary workaround until all scripts use + # python3 by default. + if sys.version_info[0] < 3: + os.execvp('python3', ['python3'] + sys.argv) + sys.exit(Main()) diff --git a/build/ios/sdk_info.py b/build/ios/sdk_info.py index 3a1e8f5..1ba4891 100755 --- a/build/ios/sdk_info.py +++ b/build/ios/sdk_info.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + # Copyright 2014 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -9,168 +11,169 @@ import itertools import os import plistlib -import re import subprocess import sys if sys.version_info.major < 3: - basestring_compat = basestring + basestring_compat = basestring else: - basestring_compat = str + basestring_compat = str # src directory ROOT_SRC_DIR = os.path.dirname( os.path.dirname(os.path.dirname(os.path.dirname( os.path.realpath(__file__))))) -# This script prints information about the build system, the operating -# system and the iOS or Mac SDK (depending on the platform "iphonesimulator", +# This script prints information about the build system, the operating system +# and the iOS or Mac SDK (depending on the platform "iphonesimulator", # "iphoneos" or "macosx" generally). def LoadPList(path): - """Loads Plist at |path| and returns it as a dictionary.""" - # Cloned from //build/apple/plist_util.py. - if sys.version_info.major == 2: - return plistlib.readPlist(path) - with open(path, 'rb') as f: - return plistlib.load(f) + """Loads Plist at |path| and returns it as a dictionary.""" + # Cloned from //build/apple/plist_util.py. + if sys.version_info.major == 2: + return plistlib.readPlist(path) + with open(path, 'rb') as f: + return plistlib.load(f) def SplitVersion(version): - """Splits the Xcode version to 3 values. + """Splits the Xcode version to 3 values. - >>> list(SplitVersion('8.2.1.1')) - ['8', '2', '1'] - >>> list(SplitVersion('9.3')) - ['9', '3', '0'] - >>> list(SplitVersion('10.0')) - ['10', '0', '0'] - """ - version = version.split('.') - return itertools.islice(itertools.chain(version, itertools.repeat('0')), 0, 3) + >>> list(SplitVersion('8.2.1.1')) + ['8', '2', '1'] + >>> list(SplitVersion('9.3')) + ['9', '3', '0'] + >>> list(SplitVersion('10.0')) + ['10', '0', '0'] + """ + version = version.split('.') + return itertools.islice(itertools.chain(version, itertools.repeat('0')), 0, + 3) def FormatVersion(version): - """Converts Xcode version to a format required for DTXcode in Info.plist + """Converts Xcode version to a format required for DTXcode in Info.plist - >>> FormatVersion('8.2.1') - '0821' - >>> FormatVersion('9.3') - '0930' - >>> FormatVersion('10.0') - '1000' - """ - major, minor, patch = SplitVersion(version) - return ('%2s%s%s' % (major, minor, patch)).replace(' ', '0') + >>> FormatVersion('8.2.1') + '0821' + >>> FormatVersion('9.3') + '0930' + >>> FormatVersion('10.0') + '1000' + """ + major, minor, patch = SplitVersion(version) + return ('%2s%s%s' % (major, minor, patch)).replace(' ', '0') def FillXcodeVersion(settings, developer_dir): - """Fills the Xcode version and build number into |settings|.""" - if developer_dir: - xcode_version_plist_path = os.path.join(developer_dir, - 'Contents/version.plist') - version_plist = LoadPList(xcode_version_plist_path) - settings['xcode_version'] = FormatVersion( - version_plist['CFBundleShortVersionString']) + """Fills the Xcode version and build number into |settings|.""" + if developer_dir: + xcode_version_plist_path = os.path.join(developer_dir, + 'Contents/version.plist') + version_plist = LoadPList(xcode_version_plist_path) + settings['xcode_version'] = FormatVersion( + version_plist['CFBundleShortVersionString']) + settings['xcode_version_int'] = int(settings['xcode_version'], 10) + settings['xcode_build'] = version_plist['ProductBuildVersion'] + return + + lines = subprocess.check_output(['xcodebuild', + '-version']).decode('UTF-8').splitlines() + settings['xcode_version'] = FormatVersion(lines[0].split()[-1]) settings['xcode_version_int'] = int(settings['xcode_version'], 10) - settings['xcode_build'] = version_plist['ProductBuildVersion'] - return - - lines = subprocess.check_output(['xcodebuild', - '-version']).decode('UTF-8').splitlines() - settings['xcode_version'] = FormatVersion(lines[0].split()[-1]) - settings['xcode_version_int'] = int(settings['xcode_version'], 10) - settings['xcode_build'] = lines[-1].split()[-1] + settings['xcode_build'] = lines[-1].split()[-1] def FillMachineOSBuild(settings): - """Fills OS build number into |settings|.""" - machine_os_build = subprocess.check_output(['sw_vers', '-buildVersion' - ]).decode('UTF-8').strip() - settings['machine_os_build'] = machine_os_build + """Fills OS build number into |settings|.""" + machine_os_build = subprocess.check_output(['sw_vers', '-buildVersion' + ]).decode('UTF-8').strip() + settings['machine_os_build'] = machine_os_build def FillSDKPathAndVersion(settings, platform, xcode_version): - """Fills the SDK path and version for |platform| into |settings|.""" - settings['sdk_path'] = subprocess.check_output( - ['xcrun', '-sdk', platform, '--show-sdk-path']).decode('UTF-8').strip() - settings['sdk_version'] = subprocess.check_output( - ['xcrun', '-sdk', platform, - '--show-sdk-version']).decode('UTF-8').strip() - settings['sdk_platform_path'] = subprocess.check_output( - ['xcrun', '-sdk', platform, - '--show-sdk-platform-path']).decode('UTF-8').strip() - settings['sdk_build'] = subprocess.check_output( - ['xcrun', '-sdk', platform, - '--show-sdk-build-version']).decode('UTF-8').strip() - settings['toolchains_path'] = os.path.join( - subprocess.check_output(['xcode-select', - '-print-path']).decode('UTF-8').strip(), - 'Toolchains/XcodeDefault.xctoolchain') + """Fills the SDK path and version for |platform| into |settings|.""" + settings['sdk_path'] = subprocess.check_output( + ['xcrun', '-sdk', platform, '--show-sdk-path']).decode('UTF-8').strip() + settings['sdk_version'] = subprocess.check_output( + ['xcrun', '-sdk', platform, + '--show-sdk-version']).decode('UTF-8').strip() + settings['sdk_platform_path'] = subprocess.check_output( + ['xcrun', '-sdk', platform, + '--show-sdk-platform-path']).decode('UTF-8').strip() + settings['sdk_build'] = subprocess.check_output( + ['xcrun', '-sdk', platform, + '--show-sdk-build-version']).decode('UTF-8').strip() + settings['toolchains_path'] = os.path.join( + subprocess.check_output(['xcode-select', + '-print-path']).decode('UTF-8').strip(), + 'Toolchains/XcodeDefault.xctoolchain') def CreateXcodeSymlinkAt(src, dst): - """Create symlink to Xcode directory at target location.""" + """Create symlink to Xcode directory at target location.""" - if not os.path.isdir(dst): - os.makedirs(dst) + if not os.path.isdir(dst): + os.makedirs(dst) - dst = os.path.join(dst, os.path.basename(src)) - updated_value = '//' + os.path.relpath(dst, ROOT_SRC_DIR) + dst = os.path.join(dst, os.path.basename(src)) + updated_value = '//' + os.path.relpath(dst, ROOT_SRC_DIR) - # Update the symlink only if it is different from the current destination. - if os.path.islink(dst): - current_src = os.readlink(dst) - if current_src == src: - return updated_value - os.unlink(dst) - sys.stderr.write('existing symlink %s points %s; want %s. Removed.' % - (dst, current_src, src)) - os.symlink(src, dst) - return updated_value + # Update the symlink only if it is different from the current destination. + if os.path.islink(dst): + current_src = os.readlink(dst) + if current_src == src: + return updated_value + os.unlink(dst) + sys.stderr.write('existing symlink %s points %s; want %s. Removed.' % + (dst, current_src, src)) + os.symlink(src, dst) + return updated_value if __name__ == '__main__': - doctest.testmod() - - parser = argparse.ArgumentParser() - parser.add_argument("--developer_dir", dest="developer_dir", required=False) - parser.add_argument("--get_sdk_info", - action="store_true", - dest="get_sdk_info", - default=False, - help="Returns SDK info in addition to xcode info.") - parser.add_argument("--get_machine_info", - action="store_true", - dest="get_machine_info", - default=False, - help="Returns machine info in addition to xcode info.") - parser.add_argument("--create_symlink_at", - action="store", - dest="create_symlink_at", - help="Create symlink of SDK at given location and " - "returns the symlinked paths as SDK info instead " - "of the original location.") - args, unknownargs = parser.parse_known_args() - if args.developer_dir: - os.environ['DEVELOPER_DIR'] = args.developer_dir - - if len(unknownargs) != 1: - sys.stderr.write('usage: %s [iphoneos|iphonesimulator|macosx]\n' % - os.path.basename(sys.argv[0])) - sys.exit(1) - - settings = {} - FillMachineOSBuild(settings) - FillXcodeVersion(settings, args.developer_dir) - if args.get_sdk_info: - FillSDKPathAndVersion(settings, unknownargs[0], settings['xcode_version']) - - for key in sorted(settings): - value = settings[key] - if args.create_symlink_at and '_path' in key: - value = CreateXcodeSymlinkAt(value, args.create_symlink_at) - if isinstance(value, basestring_compat): - value = '"%s"' % value - print('%s=%s' % (key, value)) + doctest.testmod() + + parser = argparse.ArgumentParser() + parser.add_argument("--developer_dir", dest="developer_dir", required=False) + parser.add_argument("--get_sdk_info", + action="store_true", + dest="get_sdk_info", + default=False, + help="Returns SDK info in addition to xcode info.") + parser.add_argument("--get_machine_info", + action="store_true", + dest="get_machine_info", + default=False, + help="Returns machine info in addition to xcode info.") + parser.add_argument("--create_symlink_at", + action="store", + dest="create_symlink_at", + help="Create symlink of SDK at given location and " + "returns the symlinked paths as SDK info instead " + "of the original location.") + args, unknownargs = parser.parse_known_args() + if args.developer_dir: + os.environ['DEVELOPER_DIR'] = args.developer_dir + + if len(unknownargs) != 1: + sys.stderr.write('usage: %s [iphoneos|iphonesimulator|macosx]\n' % + os.path.basename(sys.argv[0])) + sys.exit(1) + + settings = {} + FillMachineOSBuild(settings) + FillXcodeVersion(settings, args.developer_dir) + if args.get_sdk_info: + FillSDKPathAndVersion(settings, unknownargs[0], + settings['xcode_version']) + + for key in sorted(settings): + value = settings[key] + if args.create_symlink_at and '_path' in key: + value = CreateXcodeSymlinkAt(value, args.create_symlink_at) + if isinstance(value, basestring_compat): + value = '"%s"' % value + print('%s=%s' % (key, value)) diff --git a/build/ios/strip_arm64e.py b/build/ios/strip_arm64e.py index aefc35a..f7fe9fa 100644 --- a/build/ios/strip_arm64e.py +++ b/build/ios/strip_arm64e.py @@ -1,6 +1,7 @@ # Copyright 2020 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + """Strip arm64e architecture from a binary if present.""" import argparse @@ -11,59 +12,61 @@ def check_output(command): - """Returns the output from |command| or propagates error, quitting script.""" - process = subprocess.Popen( - command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - outs, errs = process.communicate() - if process.returncode: - sys.stderr.write('error: command failed with retcode %d: %s\n\n' % - (process.returncode, ' '.join(map(repr, command)))) - sys.stderr.write(errs.decode('UTF-8', errors='ignore')) - sys.exit(process.returncode) - return outs.decode('UTF-8') + """Returns the output from |command| or propagates error, quitting + script.""" + process = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + outs, errs = process.communicate() + if process.returncode: + sys.stderr.write('error: command failed with retcode %d: %s\n\n' % + (process.returncode, ' '.join(map(repr, command)))) + sys.stderr.write(errs.decode('UTF-8', errors='ignore')) + sys.exit(process.returncode) + return outs.decode('UTF-8') def check_call(command): - """Invokes |command| or propagates error.""" - check_output(command) + """Invokes |command| or propagates error.""" + check_output(command) def parse_args(args): - """Parses the command-line.""" - parser = argparse.ArgumentParser() - parser.add_argument('--input', required=True, help='Path to input binary') - parser.add_argument('--output', required=True, help='Path to output binary') - return parser.parse_args(args) + """Parses the command-line.""" + parser = argparse.ArgumentParser() + parser.add_argument('--input', required=True, help='Path to input binary') + parser.add_argument('--output', required=True, help='Path to output binary') + return parser.parse_args(args) def get_archs(path): - """Extracts the architectures present in binary at |path|.""" - outputs = check_output(["xcrun", "lipo", "-info", os.path.abspath(path)]) - return outputs.split(': ')[-1].split() + """Extracts the architectures present in binary at |path|.""" + outputs = check_output(["xcrun", "lipo", "-info", os.path.abspath(path)]) + return outputs.split(': ')[-1].split() def main(args): - parsed = parse_args(args) + parsed = parse_args(args) - outdir = os.path.dirname(parsed.output) - if not os.path.isdir(outdir): - os.makedirs(outdir) + outdir = os.path.dirname(parsed.output) + if not os.path.isdir(outdir): + os.makedirs(outdir) - if os.path.exists(parsed.output): - os.unlink(parsed.output) + if os.path.exists(parsed.output): + os.unlink(parsed.output) - # As "lipo" fails with an error if asked to remove an architecture that is - # not included, only use it if "arm64e" is present in the binary. Otherwise - # simply copy the file. - if 'arm64e' in get_archs(parsed.input): - check_output([ - "xcrun", "lipo", "-remove", "arm64e", "-output", - os.path.abspath(parsed.output), - os.path.abspath(parsed.input) - ]) - else: - shutil.copy(parsed.input, parsed.output) + # As "lipo" fails with an error if asked to remove an architecture that is + # not included, only use it if "arm64e" is present in the binary. Otherwise + # simply copy the file. + if 'arm64e' in get_archs(parsed.input): + check_output([ + "xcrun", "lipo", "-remove", "arm64e", "-output", + os.path.abspath(parsed.output), + os.path.abspath(parsed.input) + ]) + else: + shutil.copy(parsed.input, parsed.output) if __name__ == '__main__': - main(sys.argv[1:]) + main(sys.argv[1:]) diff --git a/build/win_helper.py b/build/win_helper.py index f4c9d9a..024f0c1 100644 --- a/build/win_helper.py +++ b/build/win_helper.py @@ -10,228 +10,246 @@ def _RegistryGetValue(key, value): - """Use the winreg module to obtain the value of a registry key. - - Args: - key: The registry key. - value: The particular registry value to read. - Return: - contents of the registry key's value, or None on failure. - """ - try: - root, subkey = key.split('\\', 1) - assert root == 'HKLM' # Only need HKLM for now. - with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, subkey) as hkey: - return winreg.QueryValueEx(hkey, value)[0] - except WindowsError: - return None + """Use the winreg module to obtain the value of a registry key. + + Args: + key: The registry key. + value: The particular registry value to read. + Return: + contents of the registry key's value, or None on failure. + """ + try: + root, subkey = key.split('\\', 1) + assert root == 'HKLM' # Only need HKLM for now. + with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, subkey) as hkey: + return winreg.QueryValueEx(hkey, value)[0] + except WindowsError: + return None def _ExtractImportantEnvironment(output_of_set): - """Extracts environment variables required for the toolchain to run from - a textual dump output by the cmd.exe 'set' command.""" - envvars_to_save = ( - 'include', - 'lib', - 'libpath', - 'path', - 'pathext', - 'systemroot', - 'temp', - 'tmp', - ) - env = {} - for line in output_of_set.splitlines(): - line = line.decode("utf-8") - for envvar in envvars_to_save: - if re.match(envvar + '=', line.lower()): - var, setting = line.split('=', 1) - env[var.upper()] = setting - break - for required in ('SYSTEMROOT', 'TEMP', 'TMP'): - if required not in env: - raise Exception('Environment variable "%s" ' - 'required to be set to valid path' % required) - return env + """Extracts environment variables required for the toolchain to run from + a textual dump output by the cmd.exe 'set' command.""" + envvars_to_save = ( + 'include', + 'lib', + 'libpath', + 'path', + 'pathext', + 'systemroot', + 'temp', + 'tmp', + ) + env = {} + for line in output_of_set.splitlines(): + line = line.decode("utf-8") + for envvar in envvars_to_save: + if re.match(envvar + '=', line.lower()): + var, setting = line.split('=', 1) + env[var.upper()] = setting + break + for required in ('SYSTEMROOT', 'TEMP', 'TMP'): + if required not in env: + raise Exception('Environment variable "%s" ' + 'required to be set to valid path' % required) + return env def _FormatAsEnvironmentBlock(envvar_dict): - """Format as an 'environment block' directly suitable for CreateProcess. - Briefly this is a list of key=value\0, terminated by an additional \0. See - CreateProcess() documentation for more details.""" - block = '' - nul = '\0' - for key, value in envvar_dict.items(): - block += key + '=' + value + nul - block += nul - return block + """Format as an 'environment block' directly suitable for CreateProcess. + Briefly this is a list of key=value\0, terminated by an additional \0. See + CreateProcess() documentation for more details.""" + block = '' + nul = '\0' + for key, value in envvar_dict.items(): + block += key + '=' + value + nul + block += nul + return block def _GenerateEnvironmentFiles(install_dir, out_dir, script_path): - """It's not sufficient to have the absolute path to the compiler, linker, etc. - on Windows, as those tools rely on .dlls being in the PATH. We also need to - support both x86 and x64 compilers. Different architectures require a - different compiler binary, and different supporting environment variables - (INCLUDE, LIB, LIBPATH). So, we extract the environment here, wrap all - invocations of compiler tools (cl, link, lib, rc, midl, etc.) to set up the - environment, and then do not prefix the compiler with an absolute path, - instead preferring something like "cl.exe" in the rule which will then run - whichever the environment setup has put in the path.""" - archs = ('x86', 'amd64', 'arm64') - result = [] - for arch in archs: - # Extract environment variables for subprocesses. - args = [os.path.join(install_dir, script_path)] - script_arch_name = arch - if script_path.endswith('SetEnv.cmd') and arch == 'amd64': - script_arch_name = '/x64' - if arch == 'arm64': - script_arch_name = 'x86_arm64' - args.extend((script_arch_name, '&&', 'set')) - popen = subprocess.Popen( - args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - variables, _ = popen.communicate() - if popen.returncode != 0: - raise Exception('"%s" failed with error %d' % (args, popen.returncode)) - env = _ExtractImportantEnvironment(variables) - - env_block = _FormatAsEnvironmentBlock(env) - basename = 'environment.' + arch - with open(os.path.join(out_dir, basename), 'wb') as f: - f.write(env_block.encode()) - result.append(basename) - return result + """It's not sufficient to have the absolute path to the compiler, linker, + etc. on Windows, as those tools rely on .dlls being in the PATH. We also + need to support both x86 and x64 compilers. Different architectures require + a different compiler binary, and different supporting environment variables + (INCLUDE, LIB, LIBPATH). So, we extract the environment here, wrap all + invocations of compiler tools (cl, link, lib, rc, midl, etc.) to set up the + environment, and then do not prefix the compiler with an absolute path, + instead preferring something like "cl.exe" in the rule which will then run + whichever the environment setup has put in the path.""" + archs = ('x86', 'amd64', 'arm64') + result = [] + for arch in archs: + # Extract environment variables for subprocesses. + args = [os.path.join(install_dir, script_path)] + script_arch_name = arch + if script_path.endswith('SetEnv.cmd') and arch == 'amd64': + script_arch_name = '/x64' + if arch == 'arm64': + script_arch_name = 'x86_arm64' + args.extend((script_arch_name, '&&', 'set')) + popen = subprocess.Popen(args, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + variables, _ = popen.communicate() + if popen.returncode != 0: + raise Exception('"%s" failed with error %d' % + (args, popen.returncode)) + env = _ExtractImportantEnvironment(variables) + + env_block = _FormatAsEnvironmentBlock(env) + basename = 'environment.' + arch + with open(os.path.join(out_dir, basename), 'wb') as f: + f.write(env_block.encode()) + result.append(basename) + return result def _GetEnvAsDict(arch): - """Gets the saved environment from a file for a given architecture.""" - # The environment is saved as an "environment block" (see CreateProcess() - # for details, which is the format required for ninja). We convert to a dict - # here. Drop last 2 NULs, one for list terminator, one for trailing vs. - # separator. - pairs = open(arch).read()[:-2].split('\0') - kvs = [item.split('=', 1) for item in pairs] - return dict(kvs) + """Gets the saved environment from a file for a given architecture.""" + # The environment is saved as an "environment block" (see CreateProcess() + # for details, which is the format required for ninja). We convert to a dict + # here. Drop last 2 NULs, one for list terminator, one for trailing vs. + # separator. + pairs = open(arch).read()[:-2].split('\0') + kvs = [item.split('=', 1) for item in pairs] + return dict(kvs) def _SlashSlashes(args): - """Returns args as list, with backslashes instead of slashes in args[0].""" - args = list(args) # *args is a tuple by default, which is read-only. - args[0] = args[0].replace('/', '\\') - return args + """Returns args as list, with backslashes instead of slashes in args[0].""" + args = list(args) # *args is a tuple by default, which is read-only. + args[0] = args[0].replace('/', '\\') + return args class WinTool(object): - def Dispatch(self, args): - """Dispatches a string command to a method.""" - if len(args) < 1: - raise Exception("Not enough arguments") - - method = "Exec%s" % self._CommandifyName(args[0]) - return getattr(self, method)(*args[1:]) - - def _CommandifyName(self, name_string): - """Transforms a tool name like recursive-mirror to RecursiveMirror.""" - return name_string.title().replace('-', '') - - def ExecLinkWrapper(self, arch, *args): - """Filter diagnostic output from link that looks like: - ' Creating library ui.dll.lib and object ui.dll.exp' - This happens when there are exports from the dll or exe. - """ - env = _GetEnvAsDict(arch) - args = _SlashSlashes(args) - link = subprocess.Popen(args, env=env, shell=True, stdout=subprocess.PIPE) - out, _ = link.communicate() - for line in out.splitlines(): - line = line.decode("utf-8") - if (not line.startswith(' Creating library ') and - not line.startswith('Generating code') and - not line.startswith('Finished generating code')): - print(line) - return link.returncode - - def ExecAsmWrapper(self, arch, *args): - """Filter logo banner from invocations of asm.exe.""" - env = _GetEnvAsDict(arch) - args = _SlashSlashes(args) - popen = subprocess.Popen(args, env=env, shell=True, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - out, _ = popen.communicate() - for line in out.splitlines(): - line = line.decode("utf-8") - if (not line.startswith('Copyright (C) Microsoft Corporation') and - not line.startswith('Microsoft (R) Macro Assembler') and - not line.startswith(' Assembling: ') and - line): - print(line) - return popen.returncode - - def ExecGetVisualStudioData(self, outdir, toolchain_path): - setenv_paths = [ - # cipd packaged SDKs from 10.0.19041.0 onwards. - os.path.join('Windows Kits', '10', 'bin', 'SetEnv.cmd'), - # cipd packaged SDKs prior to 10.0.19041.0. - os.path.join('win_sdk', 'bin', 'SetEnv.cmd'), - ] - - def explicit(): - for setenv_path in setenv_paths: - if os.path.exists(os.path.join(toolchain_path, setenv_path)): - return toolchain_path, setenv_path - - def env(): - from_env = os.environ.get('VSINSTALLDIR') - for setenv_path in setenv_paths: - if from_env and os.path.exists(os.path.join(from_env, setenv_path)): - return from_env, setenv_path - - def autodetect(): - # Try vswhere, which will find VS2017.2+. Note that earlier VS2017s will - # not be found. - vswhere_path = os.path.join(os.environ.get('ProgramFiles(x86)'), - 'Microsoft Visual Studio', 'Installer', 'vswhere.exe') - if os.path.exists(vswhere_path): - installation_path = subprocess.check_output( - [vswhere_path, '-latest', '-property', 'installationPath']).strip() - if installation_path: - return (installation_path.decode("utf-8"), - os.path.join('VC', 'Auxiliary', 'Build', 'vcvarsall.bat')) - - # Otherwise, try VS2015. - version = '14.0' - keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version, - r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version] - for key in keys: - path = _RegistryGetValue(key, 'InstallDir') - if not path: - continue - return (os.path.normpath(os.path.join(path, os.pardir, os.pardir)), - os.path.join('VC', 'vcvarsall.bat')) - - def fail(): raise Exception('Visual Studio installation dir not found') - - # Use an explicitly specified toolchain path, if provided and found. - # Otherwise, try using a standard environment variable. Finally, try - # autodetecting using vswhere. - install_dir, script_path = (explicit() or env() or autodetect() or fail()) - - x86_file, x64_file, arm64_file = _GenerateEnvironmentFiles( - install_dir, outdir, script_path) - # gn is unhappy with trailing backslashes. - install_dir = install_dir.rstrip('\\') - result = '''install_dir = "%s" + + def Dispatch(self, args): + """Dispatches a string command to a method.""" + if len(args) < 1: + raise Exception("Not enough arguments") + + method = "Exec%s" % self._CommandifyName(args[0]) + return getattr(self, method)(*args[1:]) + + def _CommandifyName(self, name_string): + """Transforms a tool name like recursive-mirror to RecursiveMirror.""" + return name_string.title().replace('-', '') + + def ExecLinkWrapper(self, arch, *args): + """Filter diagnostic output from link that looks like: + ' Creating library ui.dll.lib and object ui.dll.exp' + This happens when there are exports from the dll or exe. + """ + env = _GetEnvAsDict(arch) + args = _SlashSlashes(args) + link = subprocess.Popen(args, + env=env, + shell=True, + stdout=subprocess.PIPE) + out, _ = link.communicate() + for line in out.splitlines(): + line = line.decode("utf-8") + if (not line.startswith(' Creating library ') and + not line.startswith('Generating code') and + not line.startswith('Finished generating code')): + print(line) + return link.returncode + + def ExecAsmWrapper(self, arch, *args): + """Filter logo banner from invocations of asm.exe.""" + env = _GetEnvAsDict(arch) + args = _SlashSlashes(args) + popen = subprocess.Popen(args, + env=env, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, _ = popen.communicate() + for line in out.splitlines(): + line = line.decode("utf-8") + if (not line.startswith('Copyright (C) Microsoft Corporation') and + not line.startswith('Microsoft (R) Macro Assembler') and + not line.startswith(' Assembling: ') and line): + print(line) + return popen.returncode + + def ExecGetVisualStudioData(self, outdir, toolchain_path): + setenv_paths = [ + # cipd packaged SDKs from 10.0.19041.0 onwards. + os.path.join('Windows Kits', '10', 'bin', 'SetEnv.cmd'), + # cipd packaged SDKs prior to 10.0.19041.0. + os.path.join('win_sdk', 'bin', 'SetEnv.cmd'), + ] + + def explicit(): + for setenv_path in setenv_paths: + if os.path.exists(os.path.join(toolchain_path, setenv_path)): + return toolchain_path, setenv_path + + def env(): + from_env = os.environ.get('VSINSTALLDIR') + for setenv_path in setenv_paths: + if from_env and os.path.exists( + os.path.join(from_env, setenv_path)): + return from_env, setenv_path + + def autodetect(): + # Try vswhere, which will find VS2017.2+. Note that earlier VS2017s + # will not be found. + vswhere_path = os.path.join(os.environ.get('ProgramFiles(x86)'), + 'Microsoft Visual Studio', 'Installer', + 'vswhere.exe') + if os.path.exists(vswhere_path): + installation_path = subprocess.check_output( + [vswhere_path, '-latest', '-property', + 'installationPath']).strip() + if installation_path: + return (installation_path.decode("utf-8"), + os.path.join('VC', 'Auxiliary', 'Build', + 'vcvarsall.bat')) + + # Otherwise, try VS2015. + version = '14.0' + keys = [ + r'HKLM\Software\Microsoft\VisualStudio\%s' % version, + r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version + ] + for key in keys: + path = _RegistryGetValue(key, 'InstallDir') + if not path: + continue + return (os.path.normpath( + os.path.join(path, os.pardir, os.pardir)), + os.path.join('VC', 'vcvarsall.bat')) + + def fail(): + raise Exception('Visual Studio installation dir not found') + + # Use an explicitly specified toolchain path, if provided and found. + # Otherwise, try using a standard environment variable. Finally, try + # autodetecting using vswhere. + install_dir, script_path = (explicit() or env() or autodetect() or + fail()) + + x86_file, x64_file, arm64_file = _GenerateEnvironmentFiles( + install_dir, outdir, script_path) + # gn is unhappy with trailing backslashes. + install_dir = install_dir.rstrip('\\') + result = '''install_dir = "%s" x86_environment_file = "%s" x64_environment_file = "%s" arm64_environment_file = "%s"''' % (install_dir, x86_file, x64_file, arm64_file) - print(result) - return 0 + print(result) + return 0 - def ExecStamp(self, path): - """Simple stamp command.""" - open(path, 'w').close() - return 0 + def ExecStamp(self, path): + """Simple stamp command.""" + open(path, 'w').close() + return 0 if __name__ == '__main__': - sys.exit(WinTool().Dispatch(sys.argv[1:])) + sys.exit(WinTool().Dispatch(sys.argv[1:])) diff --git a/build/write_buildflag_header.py b/build/write_buildflag_header.py index 99ecb93..5e5792d 100755 --- a/build/write_buildflag_header.py +++ b/build/write_buildflag_header.py @@ -7,9 +7,9 @@ # This writes headers for build flags. See buildflag_header.gni for usage of # this system as a whole. # -# The parameters are passed in a response file so we don't have to worry -# about command line lengths. The name of the response file is passed on the -# command line. +# The parameters are passed in a response file so we don't have to worry about +# command line lengths. The name of the response file is passed on the command +# line. # # The format of the response file is: # [--flags ] @@ -50,8 +50,8 @@ def GetOptions(): # The actual output file is inside the gen dir. output = os.path.join(cmdline_options.gen_dir, cmdline_options.output) - # Definition file in GYP is newline separated, in GN they are shell formatted. - # shlex can parse both of these. + # Definition file in GYP is newline separated, in GN they are shell + # formatted. shlex can parse both of these. with open(cmdline_options.definitions, 'r') as def_file: defs = shlex.split(def_file.read()) flags_index = defs.index('--flags') From aa56c39732fe3056cc342e59f1a5563ed6ba5e5e Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 26 Feb 2025 16:05:51 -0500 Subject: [PATCH 17/32] win_helper: invoke vswhere with -products * to work with VS Build Tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a system with only the Visual Studio Build Tools workload installed (version 2022/17.13.0), but not Enterprise, Professional, or Community, `vswhere -latest -property installationPath` was not returning anything, resulting in this script failing with “Exception: Visual Studio installation dir not found” during `gn gen`. Evidently, vswhere by default only looks for Microsoft.VisualStudio.Product.{Enterprise,Professional,Community}, but not BuildTools. BuildTools alone (with a suitable SDK) should be sufficient for Crashpad development. Specifying `-products *` should allow vswhere to find the products it was previously able to locate, and also Microsoft.VisualStudio.Product.BuildTools. Change-Id: I14fb2c043b50036b26e0766a76e1fabe5a3da46a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6306504 Reviewed-by: Nico Weber --- build/win_helper.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/win_helper.py b/build/win_helper.py index 024f0c1..8f7b891 100644 --- a/build/win_helper.py +++ b/build/win_helper.py @@ -203,9 +203,10 @@ def autodetect(): 'Microsoft Visual Studio', 'Installer', 'vswhere.exe') if os.path.exists(vswhere_path): - installation_path = subprocess.check_output( - [vswhere_path, '-latest', '-property', - 'installationPath']).strip() + installation_path = subprocess.check_output([ + vswhere_path, '-products', '*', '-latest', '-property', + 'installationPath' + ]).strip() if installation_path: return (installation_path.decode("utf-8"), os.path.join('VC', 'Auxiliary', 'Build', From af17e4df94cfff4b6fa9f0be3eb222828b7cbce6 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Thu, 27 Feb 2025 12:22:23 -0500 Subject: [PATCH 18/32] Fix win-arm64 MSVC builds, and maybe other builds A GN conditional was accidentally structured: ``` if (invoker.current_cpu == "arm64") { ml = "armasm64.exe" } if (invoker.current_cpu == "x64") { ml = "ml64.exe" } else { ml = "ml.exe" } ``` The second `if` should have been `else if`. The file was not `gn format`ted or `git cl format`ted. Formatting would have made the error more readily apparent during code review and subsequent troubleshooting, as there would not have been a tendency to misread the second `if` as `else if`, making it much more evident that in the arm64 case, `ml` would have been reset to `ml.exe`: ``` if (invoker.current_cpu == "arm64") { ml = "armasm64.exe" } if (invoker.current_cpu == "x64") { ml = "ml64.exe" } else { ml = "ml.exe" } ``` Bug: 399577698 Change-Id: I390c96fe8436ecaa540fe9460d6e8582ad29e7db Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6308964 Reviewed-by: Nico Weber --- build/config/BUILD.gn | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index a3fff85..6e37773 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -342,7 +342,7 @@ config("default") { } if (mini_chromium_is_posix || mini_chromium_is_fuchsia || - mini_chromium_is_clang) { + mini_chromium_is_clang) { cflags += [ "-Wendif-labels", "-Wextra-semi", @@ -770,25 +770,25 @@ if (mini_chromium_is_win) { if (mini_chromium_is_clang) { if (invoker.current_cpu == "arm64") { - ml = "$cc --target=aarch64-pc-windows -o{{output}} /showIncludes" - is_msvc_assembler = false - depsformat = "msvc" + ml = "$cc --target=aarch64-pc-windows -o{{output}} /showIncludes" + is_msvc_assembler = false + depsformat = "msvc" + } else { + ml = rebase_path(clang_path, root_build_dir) + "/bin/llvm-ml.exe" + if (invoker.current_cpu == "x64") { + ml += " -m64" } else { - ml = rebase_path(clang_path, root_build_dir) + "/bin/llvm-ml.exe" - if (invoker.current_cpu == "x64") { - ml += " -m64" - } else { - ml += " -m32" - } + ml += " -m32" } + } } else { if (invoker.current_cpu == "arm64") { - ml = "armasm64.exe" - } if (invoker.current_cpu == "x64") { - ml = "ml64.exe" - } else { - ml = "ml.exe" - } + ml = "armasm64.exe" + } else if (invoker.current_cpu == "x64") { + ml = "ml64.exe" + } else { + ml = "ml.exe" + } } if (is_msvc_assembler) { From 7ce5c0a1bb512b895ad631ea9b015f9c3247ecf5 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 15 Mar 2025 10:58:58 -0400 Subject: [PATCH 19/32] apple: Remove unused references to SecKeychain Remove unused references to `Sec{ACL,TrustedApplication}GetTypeID` which belong to the deprecated SecKeychain API. A similar change was included in https://crrev.com/c/3791712. Bug: https://crbug.com/40233280 Change-Id: Icc3bdb592439ec056807d3fa640f2d8bcbd3f000 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6354674 Reviewed-by: Mark Mentovai Reviewed-by: Leonard Grey --- base/apple/foundation_util.h | 5 ----- base/apple/foundation_util.mm | 12 ------------ 2 files changed, 17 deletions(-) diff --git a/base/apple/foundation_util.h b/base/apple/foundation_util.h index 1654c8a..f046294 100644 --- a/base/apple/foundation_util.h +++ b/base/apple/foundation_util.h @@ -70,11 +70,6 @@ CF_CAST_DECL(CGColor); CF_CAST_DECL(CTFont); CF_CAST_DECL(CTRun); -#if !BUILDFLAG(IS_IOS) -CF_CAST_DECL(SecACL); -CF_CAST_DECL(SecTrustedApplication); -#endif - #undef CF_CAST_DECL #if defined(__OBJC__) diff --git a/base/apple/foundation_util.mm b/base/apple/foundation_util.mm index 2c63ac9..ec591a6 100644 --- a/base/apple/foundation_util.mm +++ b/base/apple/foundation_util.mm @@ -6,13 +6,6 @@ #include "base/check.h" -#if !BUILDFLAG(IS_IOS) -extern "C" { -CFTypeID SecACLGetTypeID(); -CFTypeID SecTrustedApplicationGetTypeID(); -} // extern "C" -#endif - namespace base { namespace apple { @@ -53,11 +46,6 @@ CF_CAST_DEFN(CTFont) CF_CAST_DEFN(CTRun) -#if !BUILDFLAG(IS_IOS) -CF_CAST_DEFN(SecACL) -CF_CAST_DEFN(SecTrustedApplication) -#endif - #undef CF_CAST_DEFN } // namespace apple From 9e1a21484de88f7fd445dcf7dd399e524d32a476 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Tue, 25 Mar 2025 15:56:57 +0100 Subject: [PATCH 20/32] build: Add tvOS support to C++ and GN This is the mini_chromium version of https://crrev.com/c/6306066, which added tvOS support to //build in Chromium. Like in Chromium, tvOS is treated like a subset of iOS: a build is considered to be a tvOS build when a regular iOS build's `target_platform` GN variable is set to "tvos" (by default its value is "iphoneos"). In other words, `target_os` is still "ios", and `is_ios` is true. On the C++ side, BUILDFLAG(IS_IOS_TVOS) is also set if and only if BUILDFLAG(IS_IOS) is also true (which mimics Apple's own TargetConditionals.h hierarchy given the variables we use to set the other IS_* flags). Bug: chromium:405140658 Change-Id: I3acd1f4c9226789b708e586d9f50052398678884 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6382038 Reviewed-by: Justin Cohen --- build/build_config.h | 10 ++++++++++ build/config/BUILD.gn | 19 ++++++++++++++----- build/ios/codesign.py | 2 ++ build/ios/ios_sdk.gni | 26 ++++++++++++++++++++------ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/build/build_config.h b/build/build_config.h index b8eb1f9..d4921c1 100644 --- a/build/build_config.h +++ b/build/build_config.h @@ -13,9 +13,15 @@ #if defined(TARGET_OS_OSX) && TARGET_OS_OSX #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_MAC() 1 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS() 0 +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 0 #elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_MAC() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS() 1 +#if defined(TARGET_OS_TV) && TARGET_OS_TV +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 1 +#else +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 0 +#endif // TARGET_OS_TV #endif // TARGET_OS_* #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_ANDROID() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_LINUX() 0 @@ -27,6 +33,7 @@ #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_APPLE() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_MAC() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS() 0 +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_ANDROID() 1 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_LINUX() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_CHROMEOS() 0 @@ -37,6 +44,7 @@ #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_APPLE() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_MAC() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS() 0 +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_ANDROID() 0 #if !defined(OS_CHROMEOS) #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_LINUX() 1 @@ -52,6 +60,7 @@ #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_APPLE() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_MAC() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS() 0 +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_ANDROID() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_LINUX() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_CHROMEOS() 0 @@ -62,6 +71,7 @@ #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_APPLE() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_MAC() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS() 0 +#define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_IOS_TVOS() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_ANDROID() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_LINUX() 0 #define MINI_CHROMIUM_INTERNAL_BUILDFLAG_VALUE_IS_CHROMEOS() 0 diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 6e37773..f73da64 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -224,11 +224,20 @@ config("default") { if (mini_chromium_is_ios) { if (ios_deployment_target != "") { - if (target_environment == "simulator") { - common_flags += - [ "-mios-simulator-version-min=" + ios_deployment_target ] - } else if (target_environment == "device") { - common_flags += [ "-mios-version-min=" + ios_deployment_target ] + if (target_platform == "iphoneos") { + if (target_environment == "simulator") { + common_flags += + [ "-mios-simulator-version-min=" + ios_deployment_target ] + } else if (target_environment == "device") { + common_flags += [ "-mios-version-min=" + ios_deployment_target ] + } + } else if (target_platform == "tvos") { + if (target_environment == "simulator") { + common_flags += + [ "-mtvos-simulator-version-min=" + ios_deployment_target ] + } else if (target_environment == "device") { + common_flags += [ "-mtvos-version-min=" + ios_deployment_target ] + } } } } diff --git a/build/ios/codesign.py b/build/ios/codesign.py index 03845d7..ac05d06 100644 --- a/build/ios/codesign.py +++ b/build/ios/codesign.py @@ -91,6 +91,8 @@ def Load(self): @staticmethod def Kind(platform, extension): + if platform == 'appletvsimulator' or platform == 'appletvos': + return 'tvos' if platform == 'iphonesimulator' or platform == 'iphoneos': return 'ios' if platform == 'macosx': diff --git a/build/ios/ios_sdk.gni b/build/ios/ios_sdk.gni index 535f678..dff747f 100644 --- a/build/ios/ios_sdk.gni +++ b/build/ios/ios_sdk.gni @@ -28,6 +28,10 @@ declare_args() { # default is only there for compatibility reasons and will be removed (see # crbug.com/1138425 for more details). target_environment = "" + + # The iOS-based platform being targeted. Possible values: "iphoneos", "tvos". + # The default is "iphoneos". + target_platform = "iphoneos" } if (target_environment == "") { @@ -42,12 +46,22 @@ use_ios_simulator = target_environment == "simulator" if (ios_sdk_path == "") { # Compute default target. - if (use_ios_simulator) { - ios_sdk_name = "iphonesimulator" - ios_sdk_platform = "iPhoneSimulator" - } else { - ios_sdk_name = "iphoneos" - ios_sdk_platform = "iPhoneOS" + if (target_platform == "iphoneos") { + if (use_ios_simulator) { + ios_sdk_name = "iphonesimulator" + ios_sdk_platform = "iPhoneSimulator" + } else { + ios_sdk_name = "iphoneos" + ios_sdk_platform = "iPhoneOS" + } + } else if (target_platform == "tvos") { + if (use_ios_simulator) { + ios_sdk_name = "appletvsimulator" + ios_sdk_platform = "AppleTVSimulator" + } else { + ios_sdk_name = "appletvos" + ios_sdk_platform = "AppleTVOS" + } } ios_sdk_info_args = [ "--get_sdk_info" ] From fc4d1c2053f7fb471bed271e8b0dc367c252c585 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Tue, 25 Mar 2025 15:50:24 +0100 Subject: [PATCH 21/32] base: Remove USE_ASL and corresponding usage from base/logging.cc The existing __IPHONE_OS_VERSION_MIN_REQUIRED checks were evaluating to true on tvOS builds even though ASL does not exist on the versions we are targeting. None of the platform versions that mini_chromium supports uses ASL though, so the entire code path can be removed. Bug: chromium:405140658 Change-Id: I1c03ae48f1193a6a3d2e24acfe88fd78e969c590 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6381775 Reviewed-by: Justin Cohen --- base/logging.cc | 93 +------------------------------------------------ 1 file changed, 1 insertion(+), 92 deletions(-) diff --git a/base/logging.cc b/base/logging.cc index 0385767..bab6211 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -19,29 +19,9 @@ #endif // BUILDFLAG(IS_POSIX) #if BUILDFLAG(IS_APPLE) -// In macOS 10.12 and iOS 10.0 and later ASL (Apple System Log) was deprecated -// in favor of OS_LOG (Unified Logging). -#include -#if BUILDFLAG(IS_IOS) -#if !defined(__IPHONE_10_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0 -#define USE_ASL -#endif -#else // !BUILDFLAG(IS_IOS) -#if !defined(MAC_OS_X_VERSION_10_12) || \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12 -#define USE_ASL -#endif -#endif // BUILDFLAG(IS_IOS) - -#if defined(USE_ASL) -#include -#else -#include -#endif // USE_ASL - #include +#include #include - #elif BUILDFLAG(IS_LINUX) #include #include @@ -210,76 +190,6 @@ void LogMessage::Flush() { } } -#if defined(USE_ASL) - // Use ASL when this might run on pre-10.12 systems. Unified Logging - // (os_log) was introduced in 10.12. - - const class ASLClient { - public: - explicit ASLClient(const char* asl_facility) - : client_(asl_open(nullptr, asl_facility, ASL_OPT_NO_DELAY)) {} - - ASLClient(const ASLClient&) = delete; - ASLClient& operator=(const ASLClient&) = delete; - - ~ASLClient() { asl_close(client_); } - - aslclient get() const { return client_; } - - private: - aslclient client_; - } asl_client(main_bundle_id ? main_bundle_id : "com.apple.console"); - - const class ASLMessage { - public: - ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {} - - ASLMessage(const ASLMessage&) = delete; - ASLMessage& operator=(const ASLMessage&) = delete; - - ~ASLMessage() { asl_free(message_); } - - aslmsg get() const { return message_; } - - private: - aslmsg message_; - } asl_message; - - // By default, messages are only readable by the admin group. Explicitly - // make them readable by the user generating the messages. - char euid_string[12]; - snprintf(euid_string, std::size(euid_string), "%d", geteuid()); - asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string); - - // Map Chrome log severities to ASL log levels. - const char* const asl_level_string = [](LogSeverity severity) { -#define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level) -#define ASL_LEVEL_STR_X(level) #level - switch (severity) { - case LOG_INFO: - return ASL_LEVEL_STR(ASL_LEVEL_INFO); - case LOG_WARNING: - return ASL_LEVEL_STR(ASL_LEVEL_WARNING); - case LOG_ERROR: - return ASL_LEVEL_STR(ASL_LEVEL_ERR); - case LOG_FATAL: - return ASL_LEVEL_STR(ASL_LEVEL_CRIT); - default: - return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG) - : ASL_LEVEL_STR(ASL_LEVEL_NOTICE); - } -#undef ASL_LEVEL_STR -#undef ASL_LEVEL_STR_X - }(severity_); - asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string); - - asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str()); - - asl_send(asl_client.get(), asl_message.get()); -#else - // Use Unified Logging (os_log) when this will only run on 10.12 and - // later. ASL is deprecated in 10.12. - const class OSLog { public: explicit OSLog(const char* subsystem) @@ -318,7 +228,6 @@ void LogMessage::Flush() { os_log_with_type( log.get(), os_log_type, "%{public}s", str_newline.c_str()); -#endif } #elif BUILDFLAG(IS_WIN) OutputDebugString(base::UTF8ToWide(str_newline).c_str()); From 7477036e238e54f220bed206f71036db8064dd34 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Fri, 21 Mar 2025 18:22:41 +0100 Subject: [PATCH 22/32] build: Add tvOS's id to BuildInfo.plist's UIDeviceFamily array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not doing so causes the generated bundles (e.g. Crashpad tests) to fail to run: ``` Unable to Install “crashpad_client_test” Domain: IXUserPresentableErrorDomain Code: 6 Failure Reason: This app is not made for this device. Recovery Suggestion: This app was not built to support this device family; app is compatible with ( 1, 2 ) but this device supports ( 3 ) ``` Bug: chromium:405140658 Change-Id: I9612263c3c90bf22b8084673c3f5f34dbd107f87 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6383575 Reviewed-by: Justin Cohen --- build/ios/BuildInfo.plist | 1 + 1 file changed, 1 insertion(+) diff --git a/build/ios/BuildInfo.plist b/build/ios/BuildInfo.plist index efd4e67..6b0ae1f 100644 --- a/build/ios/BuildInfo.plist +++ b/build/ios/BuildInfo.plist @@ -30,6 +30,7 @@ 1 2 + 3 From 55a0fe7707980d47baf368f0c5c0bc3378280d37 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 25 Mar 2025 12:28:50 -0400 Subject: [PATCH 23/32] Add .clang-format Change-Id: Ic6d543ba6356239a7ada1f3778ec3b667c4e51d2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6391196 Reviewed-by: Justin Cohen --- .clang-format | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..4004065 --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +# Copyright 2013 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + BasedOnStyle: Chromium, + AlignTrailingComments: false, + BinPackArguments: false, + InsertBraces: true, + InsertNewlineAtEOF: true, + Standard: Cpp11, +} From 15d1cace45803c0efb2a43630bf48bcdc15ad9e8 Mon Sep 17 00:00:00 2001 From: Paul Kirth Date: Mon, 24 Mar 2025 14:56:03 -0700 Subject: [PATCH 24/32] Fix -Wimplicit-int-conversion error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New versions of clang will start warning about more cases when the conversion happens. Bug: 402753152 Change-Id: I7e81cbe07cee18b44f4cd7fd2c90d73beb5572f5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6389255 Reviewed-by: Mark Mentovai Reviewed-by: Justin Cohen Reviewed-by: Peter Boström Reviewed-by: Leonard Grey --- base/numerics/safe_conversions_impl.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h index 36a6be9..53292b5 100644 --- a/base/numerics/safe_conversions_impl.h +++ b/base/numerics/safe_conversions_impl.h @@ -72,8 +72,9 @@ constexpr typename std::make_signed::type ConditionalNegate( static_assert(std::is_integral::value, "Type must be integral"); using SignedT = typename std::make_signed::type; using UnsignedT = typename std::make_unsigned::type; - return static_cast( - (static_cast(x) ^ -SignedT(is_negative)) + is_negative); + return static_cast((static_cast(x) ^ + static_cast(-SignedT(is_negative))) + + is_negative); } // This performs a safe, absolute value via unsigned overflow. From 035254c00a71d4f37070fcc8a50901d8e2229b8d Mon Sep 17 00:00:00 2001 From: Justin Cohen Date: Fri, 4 Apr 2025 16:20:58 -0400 Subject: [PATCH 25/32] ios: Fix compile with Xcode 16.3 XCUIAutomation.framework moved. Change-Id: I197fc2460f27677ed55289a763e7f55d2838de71 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6431318 Reviewed-by: Leonard Grey --- build/ios/rules.gni | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/build/ios/rules.gni b/build/ios/rules.gni index 42801e4..1f3019c 100644 --- a/build/ios/rules.gni +++ b/build/ios/rules.gni @@ -105,9 +105,7 @@ template("create_signed_bundle") { # Bundle ID should respect rfc1034 and replace _ with -. _xcode_product_bundle_id = - string_replace("$ios_app_bundle_id_prefix.$_output_name", - "_", - "-") + string_replace("$ios_app_bundle_id_prefix.$_output_name", "_", "-") xcode_extra_attributes = { IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target @@ -627,10 +625,16 @@ template("ios_xcuitest_test_runner_bundle") { if (xcode_version_int >= 1300) { extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework", - "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework", "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework", "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib", ] + + # Xcode 16.3 moved XCUIAutomation.framework + if (xcode_version_int < 1630) { + extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework" ] + } else { + extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/Frameworks/XCUIAutomation.framework" ] + } } # XCTestSupport framework is required as of Xcode 14.3 or later. @@ -690,6 +694,6 @@ template("ios_xcuitest_test") { template("ios_test_runner_xcuitest") { ios_xcuitest_test(target_name) { - forward_variables_from(invoker, "*", ["data_deps"]) + forward_variables_from(invoker, "*", [ "data_deps" ]) } } From 40dabd18facfcb07a633ce44c8d8c6c6b7479e54 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Fri, 4 Apr 2025 15:04:31 -0600 Subject: [PATCH 26/32] [base] Fix Windows 64-bit build warnings The Windows 64-bit build of base/logging.cc raises format specifier warnings: base/logging.cc:94:65: error: format specifies type 'unsigned int' but the argument has type 'unsigned long' [-Werror,-Wformat] 93 | return base::StringPrintf("%s (%u)", | ~~ | %lu 94 | base::WideToUTF8(msgbuf).c_str(), error_code); | ^~~~~~~~~~ base/logging.cc:97:29: error: format specifies type 'unsigned int' but the argument has type 'DWORD' (aka 'unsigned long') [-Werror,-Wformat] 96 | return base::StringPrintf("Error %u while retrieving error %u", | ~~ | %lu 97 | GetLastError(), | ^~~~~~~~~~~~~~ base/logging.cc:98:29: error: format specifies type 'unsigned int' but the argument has type 'unsigned long' [-Werror,-Wformat] 96 | return base::StringPrintf("Error %u while retrieving error %u", | ~~ | %lu 97 | GetLastError(), 98 | error_code); | ^~~~~~~~~~ This fixes the warnings. Bug: http://b/403338487 Change-Id: I41d7c2470e7093af426632b0d9dec8bd701ff237 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6434735 Reviewed-by: Justin Cohen Reviewed-by: Mark Mentovai --- base/logging.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/logging.cc b/base/logging.cc index bab6211..d0cc828 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -90,10 +90,10 @@ std::string SystemErrorCodeToString(unsigned long error_code) { if (len >= 1 && msgbuf[len - 1] == ' ') { msgbuf[len - 1] = '\0'; } - return base::StringPrintf("%s (%u)", + return base::StringPrintf("%s (%lu)", base::WideToUTF8(msgbuf).c_str(), error_code); } - return base::StringPrintf("Error %u while retrieving error %u", + return base::StringPrintf("Error %lu while retrieving error %lu", GetLastError(), error_code); } From 361ef33dcdfb1f2495fe6e44b9887fb9ab1d46af Mon Sep 17 00:00:00 2001 From: Elly Date: Wed, 23 Apr 2025 22:20:25 +0000 Subject: [PATCH 27/32] base: remove numerics namespace from byte ops That is, all the byte ops are moved from base::numerics to base. This matches the upstream chromium change in https://crrev.com/1281370. Bug: 413083268 Change-Id: I45eb81c4a411ba486f71200239a759c93fcf0198 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6484918 Reviewed-by: Mark Mentovai --- base/numerics/basic_ops_impl.h | 4 ++-- base/numerics/byte_conversions.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/base/numerics/basic_ops_impl.h b/base/numerics/basic_ops_impl.h index 5db9b2d..9e1238e 100644 --- a/base/numerics/basic_ops_impl.h +++ b/base/numerics/basic_ops_impl.h @@ -12,7 +12,7 @@ #include #include -namespace base::numerics::internal { +namespace base::internal { // The correct type to perform math operations on given values of type `T`. This // may be a larger type than `T` to avoid promotion to `int` which involves sign @@ -137,6 +137,6 @@ inline constexpr std::array ToLittleEndian(T val) { return bytes; } -} // namespace base::numerics::internal +} // namespace base::internal #endif // MINI_CHROMIUM_BASE_NUMERICS_BASIC_OPS_IMPL_H_ diff --git a/base/numerics/byte_conversions.h b/base/numerics/byte_conversions.h index 3e3e010..2cce96c 100644 --- a/base/numerics/byte_conversions.h +++ b/base/numerics/byte_conversions.h @@ -18,14 +18,14 @@ // Chromium only builds and runs on Little Endian machines. static_assert(ARCH_CPU_LITTLE_ENDIAN); -namespace base::numerics { +namespace base { // Returns a value with all bytes in |x| swapped, i.e. reverses the endianness. // TODO(pkasting): Once C++23 is available, replace with std::byteswap. template requires(std::is_integral_v) inline constexpr T ByteSwap(T value) { - return numerics::internal::SwapBytes(value); + return internal::SwapBytes(value); } // Returns a uint8_t with the value in `bytes` interpreted as the native endian @@ -437,6 +437,6 @@ inline constexpr std::array DoubleToBigEndian(double val) { return internal::ToLittleEndian(ByteSwap(std::bit_cast(val))); } -} // namespace base::numerics +} // namespace base #endif // MINI_CHROMIUM_BASE_NUMERICS_BYTE_CONVERSIONS_H_ From 4e79cec054005026ef28a4c7c3a22ef31740b897 Mon Sep 17 00:00:00 2001 From: Avi Drissman Date: Wed, 28 May 2025 11:00:10 -0400 Subject: [PATCH 28/32] Change mini_chromium's deployment target to macOS 12 Bug: 408364834 Change-Id: I9a09473f13a22788284b0ef9c5cf8f1d1d636c7f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6598174 Reviewed-by: Mark Mentovai --- build/config/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index f73da64..98533ee 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -15,7 +15,7 @@ if (mini_chromium_is_mac) { # The minimum runtime macOS version that built products are expected to run # on. If empty, the toolchain will choose its own default, typically the # older of the SDK version and the build host’s OS version. - mac_deployment_target = "10.9" + mac_deployment_target = "12.0" } } else if (mini_chromium_is_ios) { import("../ios/ios_sdk.gni") From e40cb2de8213d76190bd62524851b74f8731a216 Mon Sep 17 00:00:00 2001 From: Chris Suter Date: Wed, 23 Jul 2025 15:08:42 +1000 Subject: [PATCH 29/32] base: Switch to Fuchsia's SDK logging API Change-Id: If70af644c5eab01001621193d2ea32a12b2dd059 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6778745 Reviewed-by: Justin Cohen Reviewed-by: Mark Mentovai --- base/BUILD.gn | 4 ++-- base/logging.cc | 32 +++++++++++++++----------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/base/BUILD.gn b/base/BUILD.gn index 73f84fe..3ce2769 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn @@ -155,9 +155,9 @@ static_library("base") { ] if (defined(is_fuchsia_tree) && is_fuchsia_tree) { - deps = [ "//zircon/system/ulib/syslog" ] + deps = [ "//sdk/lib/syslog/cpp" ] } else { - deps = [ "//third_party/fuchsia/sdk/$host_os-amd64/pkg/syslog" ] + deps = [ "//third_party/fuchsia/sdk/$host_os-amd64/pkg/syslog_cpp" ] } } diff --git a/base/logging.cc b/base/logging.cc index d0cc828..7a943d4 100644 --- a/base/logging.cc +++ b/base/logging.cc @@ -30,7 +30,7 @@ #elif BUILDFLAG(IS_ANDROID) #include #elif BUILDFLAG(IS_FUCHSIA) -#include +#include #endif #include "base/check_op.h" @@ -251,36 +251,34 @@ void LogMessage::Flush() { // The Android system may truncate the string if it's too long. __android_log_write(priority, "chromium", str_newline.c_str()); #elif BUILDFLAG(IS_FUCHSIA) - fx_log_severity_t fx_severity; + fuchsia_logging::LogSeverity fx_severity; switch (severity_) { case LOG_INFO: - fx_severity = FX_LOG_INFO; + fx_severity = fuchsia_logging::LogSeverity::Info; break; case LOG_WARNING: - fx_severity = FX_LOG_WARNING; + fx_severity = fuchsia_logging::LogSeverity::Warn; break; case LOG_ERROR: - fx_severity = FX_LOG_ERROR; + fx_severity = fuchsia_logging::LogSeverity::Error; break; case LOG_FATAL: - fx_severity = FX_LOG_FATAL; + fx_severity = fuchsia_logging::LogSeverity::Fatal; break; default: - fx_severity = FX_LOG_INFO; + fx_severity = fuchsia_logging::LogSeverity::Info; break; } - // Temporarily remove the trailing newline from |str_newline|'s C-string - // representation, since fx_logger will add a newline of its own. - str_newline.pop_back(); + // Fuchsia's logger doesn't want the trailing newline. + std::string_view message(str_newline); + message.remove_suffix(1); + message.remove_prefix(message_start_); // Ideally the tag would be the same as the caller, but this is not // supported right now. - fx_logger_log_with_source(fx_log_get_logger(), - fx_severity, - /*tag=*/nullptr, - file_path_, - line_, - str_newline.c_str() + message_start_); - str_newline.push_back('\n'); + fuchsia_logging::LogMessage( + fx_severity, file_path_, line_, nullptr, nullptr) + .stream() + << message; #endif // BUILDFLAG(IS_*) } From eef0dc3c2a8be344d69077057d62900c13f6299b Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Fri, 15 Aug 2025 11:17:21 -0700 Subject: [PATCH 30/32] Convert base::StringPiece to std::string_view Generated with the script in https://g-issues.chromium.org/issues/40506050#comment344 Bug: 40506050 Change-Id: I065943ec0a6d763ffe64e97a5c4a698f40848a91 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6851626 Reviewed-by: Mark Mentovai --- base/metrics/persistent_histogram_allocator.h | 7 ++++--- base/strings/pattern.cc | 6 ++++-- base/strings/pattern.h | 6 +++--- base/strings/strcat.cc | 3 ++- base/strings/strcat.h | 16 ++++++++-------- base/strings/string_number_conversions.cc | 13 +++++++------ base/strings/string_number_conversions.h | 15 +++++++-------- base/strings/string_piece.h | 17 +++++++++-------- base/strings/utf_string_conversions.cc | 6 +++--- base/strings/utf_string_conversions.h | 7 +++---- 10 files changed, 50 insertions(+), 46 deletions(-) diff --git a/base/metrics/persistent_histogram_allocator.h b/base/metrics/persistent_histogram_allocator.h index b67a136..fc34907 100644 --- a/base/metrics/persistent_histogram_allocator.h +++ b/base/metrics/persistent_histogram_allocator.h @@ -8,8 +8,9 @@ #include #include +#include + #include "base/files/file_path.h" -#include "base/strings/string_piece.h" // This file is a non-functional stub of the Chromium base interface to allow // Crashpad to set up and tear down histogram storage when built against @@ -25,11 +26,11 @@ class GlobalHistogramAllocator { static bool CreateWithActiveFileInDir(const base::FilePath&, size_t, uint64_t, - base::StringPiece sp) { + std::string_view sp) { return false; } - void CreateTrackingHistograms(base::StringPiece) {} + void CreateTrackingHistograms(std::string_view) {} void DeletePersistentLocation() {} static GlobalHistogramAllocator* Get() { return nullptr; } diff --git a/base/strings/pattern.cc b/base/strings/pattern.cc index cc747aa..12f11ae 100644 --- a/base/strings/pattern.cc +++ b/base/strings/pattern.cc @@ -4,6 +4,8 @@ #include "base/strings/pattern.h" +#include + #include "base/third_party/icu/icu_utf.h" namespace base { @@ -142,12 +144,12 @@ struct NextCharUTF16 { } // namespace -bool MatchPattern(StringPiece eval, StringPiece pattern) { +bool MatchPattern(std::string_view eval, std::string_view pattern) { return MatchPatternT(eval.data(), eval.data() + eval.size(), pattern.data(), pattern.data() + pattern.size(), NextCharUTF8()); } -bool MatchPattern(StringPiece16 eval, StringPiece16 pattern) { +bool MatchPattern(std::u16string_view eval, std::u16string_view pattern) { return MatchPatternT(eval.data(), eval.data() + eval.size(), pattern.data(), pattern.data() + pattern.size(), NextCharUTF16()); } diff --git a/base/strings/pattern.h b/base/strings/pattern.h index 20c13c7..45cf76b 100644 --- a/base/strings/pattern.h +++ b/base/strings/pattern.h @@ -5,7 +5,7 @@ #ifndef BASE_STRINGS_PATTERN_H_ #define BASE_STRINGS_PATTERN_H_ -#include "base/strings/string_piece.h" +#include namespace base { @@ -14,8 +14,8 @@ namespace base { // // The backslash character (\) is an escape character for * and ?. // ? matches 0 or 1 character, while * matches 0 or more characters. -bool MatchPattern(StringPiece string, StringPiece pattern); -bool MatchPattern(StringPiece16 string, StringPiece16 pattern); +bool MatchPattern(std::string_view string, std::string_view pattern); +bool MatchPattern(std::u16string_view string, std::u16string_view pattern); } // namespace base diff --git a/base/strings/strcat.cc b/base/strings/strcat.cc index f322fc3..4ce6ddd 100644 --- a/base/strings/strcat.cc +++ b/base/strings/strcat.cc @@ -5,12 +5,13 @@ #include "base/strings/strcat.h" #include +#include #include "base/strings/strcat_internal.h" namespace base { -std::string StrCat(span pieces) { +std::string StrCat(span pieces) { return internal::StrCatT(pieces); } diff --git a/base/strings/strcat.h b/base/strings/strcat.h index d26c2fc..330656a 100644 --- a/base/strings/strcat.h +++ b/base/strings/strcat.h @@ -6,9 +6,9 @@ #define BASE_STRINGS_STRCAT_H_ #include +#include #include "base/containers/span.h" -#include "base/strings/string_piece.h" #include "build/build_config.h" #if BUILDFLAG(IS_WIN) @@ -32,7 +32,7 @@ namespace base { // StrCat can see all arguments at once, so it can allocate one return buffer // of exactly the right size and copy once, as opposed to a sequence of // operator+ which generates a series of temporary strings, copying as it goes. -// And by using StringPiece arguments, StrCat can avoid creating temporary +// And by using std::string_view arguments, StrCat can avoid creating temporary // string objects for char* constants. // // ALTERNATIVES @@ -49,15 +49,15 @@ namespace base { // and the call sites look nice. // // As-written Abseil's helper class for numbers generates slightly more code -// than the raw StringPiece version. We can de-inline the helper class' -// constructors which will cause the StringPiece constructors to be de-inlined -// for this call and generate slightly less code. This is something we can -// explore more in the future. +// than the raw std::string_view version. We can de-inline the helper class' +// constructors which will cause the std::string_view constructors to be +// de-inlined for this call and generate slightly less code. This is something +// we can explore more in the future. -[[nodiscard]] std::string StrCat(span pieces); +[[nodiscard]] std::string StrCat(span pieces); // Initializer list forwards to the array version. -inline std::string StrCat(std::initializer_list pieces) { +inline std::string StrCat(std::initializer_list pieces) { return StrCat(make_span(pieces)); } diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc index cda1eaf..4e40d91 100644 --- a/base/strings/string_number_conversions.cc +++ b/base/strings/string_number_conversions.cc @@ -8,6 +8,7 @@ #include #include +#include namespace base { @@ -222,34 +223,34 @@ typedef BaseHexIteratorRangeToIntTraits } // namespace -bool StringToInt(const StringPiece& input, int* output) { +bool StringToInt(std::string_view input, int* output) { return IteratorRangeToNumber::Invoke(input.begin(), input.end(), output); } -bool StringToUint(const StringPiece& input, unsigned int* output) { +bool StringToUint(std::string_view input, unsigned int* output) { return IteratorRangeToNumber::Invoke(input.begin(), input.end(), output); } -bool StringToInt64(const StringPiece& input, int64_t* output) { +bool StringToInt64(std::string_view input, int64_t* output) { return IteratorRangeToNumber::Invoke( input.begin(), input.end(), output); } -bool StringToUint64(const StringPiece& input, uint64_t* output) { +bool StringToUint64(std::string_view input, uint64_t* output) { return IteratorRangeToNumber::Invoke( input.begin(), input.end(), output); } -bool StringToSizeT(const StringPiece& input, size_t* output) { +bool StringToSizeT(std::string_view input, size_t* output) { return IteratorRangeToNumber::Invoke( input.begin(), input.end(), output); } -bool HexStringToInt(const StringPiece& input, int* output) { +bool HexStringToInt(std::string_view input, int* output) { return IteratorRangeToNumber::Invoke( input.begin(), input.end(), output); } diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h index 3f781c0..989b7ab 100644 --- a/base/strings/string_number_conversions.h +++ b/base/strings/string_number_conversions.h @@ -8,19 +8,18 @@ #include #include +#include #include -#include "base/strings/string_piece.h" - namespace base { -bool StringToInt(const StringPiece& input, int* output); -bool StringToUint(const StringPiece& input, unsigned int* output); -bool StringToInt64(const StringPiece& input, int64_t* output); -bool StringToUint64(const StringPiece& input, uint64_t* output); -bool StringToSizeT(const StringPiece& input, size_t* output); +bool StringToInt(std::string_view input, int* output); +bool StringToUint(std::string_view input, unsigned int* output); +bool StringToInt64(std::string_view input, int64_t* output); +bool StringToUint64(std::string_view input, uint64_t* output); +bool StringToSizeT(std::string_view input, size_t* output); -bool HexStringToInt(const StringPiece& input, int* output); +bool HexStringToInt(std::string_view input, int* output); bool HexStringToBytes(const std::string& input, std::vector* output); } // namespace base diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h index a6a448b..336de56 100644 --- a/base/strings/string_piece.h +++ b/base/strings/string_piece.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace base { @@ -158,17 +159,17 @@ std::ostream& operator<<(std::ostream& ostream, return ostream; } -typedef BasicStringPiece StringPiece; -typedef BasicStringPiece StringPiece16; +typedef BasicStringPiece std::string_view; +typedef BasicStringPiece std::u16string_view; -inline bool operator==(const StringPiece& x, const StringPiece& y) { +inline bool operator==(std::string_view x, std::string_view y) { if (x.size() != y.size()) return false; return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; } -inline bool operator==(const StringPiece16& x, const StringPiece16& y) { +inline bool operator==(std::u16string_view x, std::u16string_view y) { if (x.size() != y.size()) return false; @@ -186,13 +187,13 @@ inline bool operator==(const StringPiece16& x, const StringPiece16& y) { return result; struct StringPieceHash { - std::size_t operator()(const StringPiece& sp) const { - HASH_STRING_PIECE(StringPiece, sp); + std::size_t operator()(std::string_view sp) const { + HASH_STRING_PIECE(std::string_view, sp); } }; struct StringPiece16Hash { - std::size_t operator()(const StringPiece16& sp16) const { - HASH_STRING_PIECE(StringPiece16, sp16); + std::size_t operator()(std::u16string_view sp16) const { + HASH_STRING_PIECE(std::u16string_view, sp16); } }; diff --git a/base/strings/utf_string_conversions.cc b/base/strings/utf_string_conversions.cc index a1c243c..8a7664c 100644 --- a/base/strings/utf_string_conversions.cc +++ b/base/strings/utf_string_conversions.cc @@ -42,7 +42,7 @@ bool UTF8ToUTF16(const char* src, size_t src_len, std::u16string* output) { return ConvertUnicode(src, src_len, output); } -std::u16string UTF8ToUTF16(const StringPiece& utf8) { +std::u16string UTF8ToUTF16(std::string_view utf8) { std::u16string ret; UTF8ToUTF16(utf8.data(), utf8.length(), &ret); return ret; @@ -53,7 +53,7 @@ bool UTF16ToUTF8(const char16_t* src, size_t src_len, std::string* output) { return ConvertUnicode(src, src_len, output); } -std::string UTF16ToUTF8(const StringPiece16& utf16) { +std::string UTF16ToUTF8(std::u16string_view utf16) { std::string ret; UTF16ToUTF8(utf16.data(), utf16.length(), &ret); return ret; @@ -67,7 +67,7 @@ std::string WideToUTF8(std::wstring_view wide) { return ret; } -std::wstring UTF8ToWide(StringPiece utf8) { +std::wstring UTF8ToWide(std::string_view utf8) { std::u16string utf16 = UTF8ToUTF16(utf8); return std::wstring(reinterpret_cast(utf16.data()), utf16.size()); diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h index 64c79c2..7de2b81 100644 --- a/base/strings/utf_string_conversions.h +++ b/base/strings/utf_string_conversions.h @@ -8,19 +8,18 @@ #include #include -#include "base/strings/string_piece.h" #include "build/build_config.h" namespace base { bool UTF8ToUTF16(const char* src, size_t src_len, std::u16string* output); -std::u16string UTF8ToUTF16(const StringPiece& utf8); +std::u16string UTF8ToUTF16(std::string_view utf8); bool UTF16ToUTF8(const char16_t* src, size_t src_len, std::string* output); -std::string UTF16ToUTF8(const StringPiece16& utf16); +std::string UTF16ToUTF8(std::u16string_view utf16); #if defined(WCHAR_T_IS_16_BIT) std::string WideToUTF8(std::wstring_view wide); -std::wstring UTF8ToWide(StringPiece utf8); +std::wstring UTF8ToWide(std::string_view utf8); #endif // defined(WCHAR_T_IS_16_BIT) } // namespace From eef885b0bb80dab8e9d79b9dc0c050a1c8e50c0b Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Fri, 15 Aug 2025 12:54:09 -0700 Subject: [PATCH 31/32] Remove remaining references to StringPiece Change-Id: I43ab5738e14e9bf8a4837f706f9d04887d09c84d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6854520 Reviewed-by: Mark Mentovai --- base/BUILD.gn | 1 - base/strings/string_number_conversions.cc | 18 +- base/strings/string_piece.h | 202 ---------------------- 3 files changed, 10 insertions(+), 211 deletions(-) delete mode 100644 base/strings/string_piece.h diff --git a/base/BUILD.gn b/base/BUILD.gn index 3ce2769..ba6f6e5 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn @@ -63,7 +63,6 @@ static_library("base") { "strings/strcat_internal.h", "strings/string_number_conversions.cc", "strings/string_number_conversions.h", - "strings/string_piece.h", "strings/string_util.h", "strings/stringprintf.cc", "strings/stringprintf.h", diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc index 4e40d91..f46f04b 100644 --- a/base/strings/string_number_conversions.cc +++ b/base/strings/string_number_conversions.cc @@ -186,25 +186,27 @@ class BaseIteratorRangeToNumberTraits { static constexpr int kBase = BASE; }; -typedef BaseIteratorRangeToNumberTraits +typedef BaseIteratorRangeToNumberTraits IteratorRangeToIntTraits; -typedef BaseIteratorRangeToNumberTraits +typedef BaseIteratorRangeToNumberTraits IteratorRangeToUintTraits; -typedef BaseIteratorRangeToNumberTraits IteratorRangeToInt64Traits; -typedef BaseIteratorRangeToNumberTraits IteratorRangeToUint64Traits; -typedef BaseIteratorRangeToNumberTraits IteratorRangeToSizeTTraits; @@ -218,7 +220,7 @@ class BaseHexIteratorRangeToIntTraits } }; -typedef BaseHexIteratorRangeToIntTraits +typedef BaseHexIteratorRangeToIntTraits HexIteratorRangeToIntTraits; } // namespace diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h deleted file mode 100644 index 336de56..0000000 --- a/base/strings/string_piece.h +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2006-2008 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MINI_CHROMIUM_BASE_STRINGS_STRING_PIECE_H_ -#define MINI_CHROMIUM_BASE_STRINGS_STRING_PIECE_H_ - -#include -#include -#include -#include -#include - -namespace base { - -template -class BasicStringPiece { - public: - typedef typename StringType::traits_type traits_type; - typedef typename StringType::value_type value_type; - typedef typename StringType::size_type size_type; - typedef typename StringType::difference_type difference_type; - typedef const value_type& reference; - typedef const value_type& const_reference; - typedef const value_type* pointer; - typedef const value_type* const_pointer; - typedef const value_type* const_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - static const size_type npos; - - BasicStringPiece() - : pointer_(NULL), - length_(0) { - } - - BasicStringPiece(const value_type* string) - : pointer_(string), - length_((string == NULL) ? 0 : traits_type::length(string)) { - } - - BasicStringPiece(const StringType& string) - : pointer_(string.data()), - length_(string.size()) { - } - - BasicStringPiece(const value_type* offset, size_type length) - : pointer_(offset), - length_(length) { - } - - BasicStringPiece(const typename StringType::const_iterator& begin, - const typename StringType::const_iterator& end) - : pointer_((end > begin) ? &(*begin) : NULL), - length_((end > begin) ? static_cast(end - begin) : 0) { - } - - value_type operator[](size_type index) const { return pointer_[index]; } - - const value_type* data() const { return pointer_; } - - const_iterator begin() const { return pointer_; } - const_iterator end() const { return pointer_ + length_; } - const_reverse_iterator rbegin() const { - return const_reverse_iterator(pointer_ + length_); - } - const_reverse_iterator rend() const { - return const_reverse_iterator(pointer_); - } - - bool empty() const { return length_ == 0; } - size_type size() const { return length_; } - size_type length() const { return length_; } - size_type max_size() const { return length_; } - size_type capacity() const { return length_; } - - static int wordmemcmp(const value_type* p, - const value_type* p2, - size_type N) { - return StringType::traits_type::compare(p, p2, N); - } - - void clear() { - pointer_ = NULL; - length_ = 0; - } - - int compare(const BasicStringPiece& that) const { - int result = traits_type::compare(pointer_, - that.pointer_, - std::min(length_, that.length_)); - if (result == 0) { - if (length_ < that.length_) { - result = -1; - } else if (length_ > that.length_) { - result = 1; - } - } - return result; - } - - BasicStringPiece substr(size_type position = 0, - size_type count = npos) const { - position = std::min(position, size()); - count = std::min(count, size() - position); - return BasicStringPiece(data() + position, count); - } - - size_type copy(value_type* dest, - size_type count, - size_type position = 0) const { - size_type ret = std::min(size() - position, count); - traits_type::copy(dest, data() + position, ret); - return ret; - } - - size_type find(const BasicStringPiece& str, size_type pos) const { - if (pos >= size()) { - return npos; - } - const_iterator result = std::search(begin() + pos, - end(), - str.begin(), - str.end()); - size_type xpos = static_cast(result - begin()); - return xpos + str.size() <= size() ? xpos : npos; - } - - size_type find(value_type c, size_type pos) const { - if (pos >= size()) { - return npos; - } - const_iterator result = std::find(begin() + pos, end(), c); - return result != end() ? static_cast(result - begin()) : npos; - } - - void set(const value_type* string) { - pointer_ = string; - length_ = string ? traits_type::length(string) : 0; - } - - StringType as_string() const { - return empty() ? StringType() : StringType(data(), size()); - } - - private: - const value_type* pointer_; - size_type length_; -}; - -template -const typename BasicStringPiece::size_type - BasicStringPiece::npos = StringType::npos; - -template -std::ostream& operator<<(std::ostream& ostream, - const BasicStringPiece& string_piece) { - ostream.write(string_piece.data(), string_piece.size()); - return ostream; -} - -typedef BasicStringPiece std::string_view; -typedef BasicStringPiece std::u16string_view; - -inline bool operator==(std::string_view x, std::string_view y) { - if (x.size() != y.size()) - return false; - - return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; -} - -inline bool operator==(std::u16string_view x, std::u16string_view y) { - if (x.size() != y.size()) - return false; - - return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0; -} - -// This is a custom hash function. We don't use the ones already defined for -// string and std::u16string directly because it would require the string -// constructors to be called, which we don't want. -#define HASH_STRING_PIECE(StringPieceType, string_piece) \ - std::size_t result = 0; \ - for (StringPieceType::const_iterator i = string_piece.begin(); \ - i != string_piece.end(); ++i) \ - result = (result * 131) + *i; \ - return result; - -struct StringPieceHash { - std::size_t operator()(std::string_view sp) const { - HASH_STRING_PIECE(std::string_view, sp); - } -}; -struct StringPiece16Hash { - std::size_t operator()(std::u16string_view sp16) const { - HASH_STRING_PIECE(std::u16string_view, sp16); - } -}; - -} // namespace base; - -#endif // MINI_CHROMIUM_BASE_STRINGS_STRING_PIECE_H_ From e5a8d550e530d504c792af8ec7dbcbd3d80544df Mon Sep 17 00:00:00 2001 From: Venkatesh Srinivas Date: Fri, 25 Jul 2025 01:54:52 +0000 Subject: [PATCH 32/32] mini_chromium: Remove Barrier_AtomicIncrement, no longer used The last user of Barrier_AtomicIncrement was crashpad_client_win.cc; https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6785253 removes the use, so we can remove the implementation. Bug: 40175832 Change-Id: Id2884c37e1788bc471b02831885a6eb213824654 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/mini_chromium/+/6786567 Reviewed-by: Mark Mentovai Reviewed-by: Benoit Lize --- base/atomicops.h | 4 ---- base/atomicops_internals_atomicword_compat.h | 6 ------ base/atomicops_internals_portable.h | 10 ---------- 3 files changed, 20 deletions(-) diff --git a/base/atomicops.h b/base/atomicops.h index 00d7f75..5ecbac2 100644 --- a/base/atomicops.h +++ b/base/atomicops.h @@ -87,9 +87,6 @@ Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); // *ptr with the increment applied. This routine implies no memory barriers. Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); -Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment); - // These following lower-level operations are typically useful only to people // implementing higher-level synchronization operations like spinlocks, // mutexes, and condition-variables. They combine CompareAndSwap(), a load, or @@ -122,7 +119,6 @@ Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 new_value); Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); -Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h index c2fdad9..b5d391b 100644 --- a/base/atomicops_internals_atomicword_compat.h +++ b/base/atomicops_internals_atomicword_compat.h @@ -42,12 +42,6 @@ inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, reinterpret_cast(ptr), increment); } -inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr, - AtomicWord increment) { - return Barrier_AtomicIncrement( - reinterpret_cast(ptr), increment); -} - inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, AtomicWord old_value, AtomicWord new_value) { diff --git a/base/atomicops_internals_portable.h b/base/atomicops_internals_portable.h index 88e2d2d..a3bda60 100644 --- a/base/atomicops_internals_portable.h +++ b/base/atomicops_internals_portable.h @@ -78,11 +78,6 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, ->fetch_add(increment, std::memory_order_relaxed); } -inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, - Atomic32 increment) { - return increment + ((AtomicLocation32)ptr)->fetch_add(increment); -} - inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { @@ -161,11 +156,6 @@ inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, ->fetch_add(increment, std::memory_order_relaxed); } -inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, - Atomic64 increment) { - return increment + ((AtomicLocation64)ptr)->fetch_add(increment); -} - inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, Atomic64 new_value) {