Merge bitcoin/bitcoin#22546: build, qt: Fix make deploy on M1-based macOS with system frameworks

1513727e2b build, qt: (Re-)sign package (Hennadii Stepanov)
c26a0a5af7 build, qt: Align frameworks with macOS codesign tool requirements (Hennadii Stepanov)

Pull request description:

  Fixes #22403

  This PR follows Apple [docs](https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-universal-apps-release-notes):
  >  - New in macOS 11 on Macs with Apple silicon, and starting in macOS Big Sur 11 beta 6, the operating system enforces that any executable must be signed before it’s allowed to run. There isn’t a specific identity requirement for this signature: a simple ad-hoc signature is sufficient...
  >  - ... If you use a custom workflow involving tools that modify a binary after linking (e.g. `strip` or `install_name_tool`) you might need to manually call `codesign` as an additional build phase to properly ad-hoc sign your binary. These new signatures are not bound to the specific machine that was used to build the executable, they can be verified on any other system and will be sufficient to comply with the new default code signing requirement on Macs with Apple silicon...

  When building with system Qt frameworks (i.e., without depends), a new string has been added to the `make deploy` log on M1-based macOS:
  ```
  % make deploy
  ...
  + Generating .DS_Store +
  dist/Bitcoin-Qt.app: replacing existing signature
  + Preparing .dmg disk image +
  ...
  ```

  This PR does not change build system behavior:
  - when building with depends
  - on Intel-based macOS

ACKs for top commit:
  jarolrod:
    ACK 1513727e2b
  fanquake:
    ACK 1513727e2b - although didn't test on M1 hardware. Given the forced signing is scoped to only occur when running the deploy script on macOS, this doesn't interfere with our release signing.

Tree-SHA512: 3aa778fdd6ddb54f029f632f2fe52c2ae3bb197ba564cb776493aa5c3a655bd51d10ccbe6c007372d717e9b01fc4193dd5c29ea0bc7e069dcae7e991ae259f0c
This commit is contained in:
fanquake 2022-02-23 15:44:30 +00:00
commit 077cfffebd
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1

View file

@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import sys, re, os, shutil, stat, os.path
import sys, re, os, platform, shutil, stat, subprocess, os.path
from argparse import ArgumentParser
from ds_store import DSStore
from mac_alias import Alias
@ -244,49 +244,47 @@ def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional
fromPath = framework.sourceFilePath
toDir = os.path.join(path, framework.destinationDirectory)
toPath = os.path.join(toDir, framework.binaryName)
if not os.path.exists(fromPath):
raise RuntimeError(f"No file at {fromPath}")
if os.path.exists(toPath):
return None # Already there
if not os.path.exists(toDir):
os.makedirs(toDir)
shutil.copy2(fromPath, toPath)
if verbose:
print("Copied:", fromPath)
print(" to:", toPath)
if framework.isDylib():
if not os.path.exists(fromPath):
raise RuntimeError(f"No file at {fromPath}")
if os.path.exists(toPath):
return None # Already there
if not os.path.exists(toDir):
os.makedirs(toDir)
shutil.copy2(fromPath, toPath)
if verbose:
print("Copied:", fromPath)
print(" to:", toPath)
else:
to_dir = os.path.join(path, "Contents", "Frameworks", framework.frameworkName)
if os.path.exists(to_dir):
return None # Already there
from_dir = framework.frameworkPath
if not os.path.exists(from_dir):
raise RuntimeError(f"No directory at {from_dir}")
shutil.copytree(from_dir, to_dir, symlinks=True)
if verbose:
print("Copied:", from_dir)
print(" to:", to_dir)
headers_link = os.path.join(to_dir, "Headers")
if os.path.exists(headers_link):
os.unlink(headers_link)
headers_dir = os.path.join(to_dir, framework.binaryDirectory, "Headers")
if os.path.exists(headers_dir):
shutil.rmtree(headers_dir)
permissions = os.stat(toPath)
if not permissions.st_mode & stat.S_IWRITE:
os.chmod(toPath, permissions.st_mode | stat.S_IWRITE)
if not framework.isDylib(): # Copy resources for real frameworks
linkfrom = os.path.join(path, "Contents","Frameworks", framework.frameworkName, "Versions", "Current")
linkto = framework.version
if not os.path.exists(linkfrom):
os.symlink(linkto, linkfrom)
print("Linked:", linkfrom, "->", linkto)
fromResourcesDir = framework.sourceResourcesDirectory
if os.path.exists(fromResourcesDir):
toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory)
shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True)
if verbose:
print("Copied resources:", fromResourcesDir)
print(" to:", toResourcesDir)
fromContentsDir = framework.sourceVersionContentsDirectory
if not os.path.exists(fromContentsDir):
fromContentsDir = framework.sourceContentsDirectory
if os.path.exists(fromContentsDir):
toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory)
shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
if verbose:
print("Copied Contents:", fromContentsDir)
print(" to:", toContentsDir)
return toPath
def deployFrameworks(frameworks: List[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo:
@ -543,6 +541,9 @@ ds.close()
# ------------------------------------------------
if platform.system() == "Darwin":
subprocess.check_call(f"codesign --deep --force --sign - {target}", shell=True)
if config.dmg is not None:
print("+ Preparing .dmg disk image +")