Skip to content

Commit

Permalink
Merge bitcoin#22546: build, qt: Fix make deploy on M1-based macOS w…
Browse files Browse the repository at this point in the history
…ith system frameworks

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

Pull request description:

  Fixes bitcoin#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 1513727
  fanquake:
    ACK 1513727 - 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
  • Loading branch information
fanquake committed Feb 23, 2022
2 parents 358fe77 + 1513727 commit 077cfff
Showing 1 changed file with 40 additions and 39 deletions.
79 changes: 40 additions & 39 deletions contrib/macdeploy/macdeployqtplus
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 +")
Expand Down

0 comments on commit 077cfff

Please sign in to comment.