Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32#3# Copyright (C) 2011 Patrick "p2k" Schneider <[email protected]>4#5# This program is free software: you can redistribute it and/or modify6# it under the terms of the GNU General Public License as published by7# the Free Software Foundation, either version 3 of the License, or8# (at your option) any later version.9#10# This program is distributed in the hope that it will be useful,11# but WITHOUT ANY WARRANTY; without even the implied warranty of12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13# GNU General Public License for more details.14#15# You should have received a copy of the GNU General Public License16# along with this program. If not, see <http://www.gnu.org/licenses/>.17#19import sys, re, os, platform, shutil, stat, subprocess, os.path20from argparse import ArgumentParser21from pathlib import Path22from subprocess import PIPE, run23from typing import Optional25# This is ported from the original macdeployqt with modifications27class FrameworkInfo(object):28def __init__(self):29self.frameworkDirectory = ""30self.frameworkName = ""31self.frameworkPath = ""32self.binaryDirectory = ""33self.binaryName = ""34self.binaryPath = ""35self.version = ""36self.installName = ""37self.deployedInstallName = ""38self.sourceFilePath = ""39self.destinationDirectory = ""40self.sourceResourcesDirectory = ""41self.sourceVersionContentsDirectory = ""42self.sourceContentsDirectory = ""43self.destinationResourcesDirectory = ""44self.destinationVersionContentsDirectory = ""46def __eq__(self, other):47if self.__class__ == other.__class__:48return self.__dict__ == other.__dict__49else:50return False52def __str__(self):53return f""" Framework name: {self.frameworkName}54Framework directory: {self.frameworkDirectory}55Framework path: {self.frameworkPath}56Binary name: {self.binaryName}57Binary directory: {self.binaryDirectory}58Binary path: {self.binaryPath}59Version: {self.version}60Install name: {self.installName}61Deployed install name: {self.deployedInstallName}62Source file Path: {self.sourceFilePath}63Deployed Directory (relative to bundle): {self.destinationDirectory}64"""66def isDylib(self):67return self.frameworkName.endswith(".dylib")69def isQtFramework(self):70if self.isDylib():71return self.frameworkName.startswith("libQt")72else:73return self.frameworkName.startswith("Qt")75reOLine = re.compile(r'^(.+) \(compatibility version [0-9.]+, current version [0-9.]+\)$')76bundleFrameworkDirectory = "Contents/Frameworks"77bundleBinaryDirectory = "Contents/MacOS"79@classmethod80def fromLibraryLine(cls, line: str) -> Optional['FrameworkInfo']:81# Note: line must be trimmed82if line == "":83return None85# Don't deploy system libraries86if line.startswith("/System/Library/") or line.startswith("@executable_path") or line.startswith("/usr/lib/"):87return None89m = cls.reOLine.match(line)90if m is None:91raise RuntimeError(f"Line could not be parsed: {line}")93path = m.group(1)95info = cls()96info.sourceFilePath = path97info.installName = path99if path.endswith(".dylib"):100dirname, filename = os.path.split(path)101info.frameworkName = filename102info.frameworkDirectory = dirname103info.frameworkPath = path105info.binaryDirectory = dirname106info.binaryName = filename107info.binaryPath = path108info.version = "-"110info.installName = path111info.deployedInstallName = f"@executable_path/../Frameworks/{info.binaryName}"112info.sourceFilePath = path113info.destinationDirectory = cls.bundleFrameworkDirectory114else:115parts = path.split("/")116i = 0117# Search for the .framework directory118for part in parts:119if part.endswith(".framework"):120break121i += 1122if i == len(parts):123raise RuntimeError(f"Could not find .framework or .dylib in line: {line}")125info.frameworkName = parts[i]126info.frameworkDirectory = "/".join(parts[:i])127info.frameworkPath = os.path.join(info.frameworkDirectory, info.frameworkName)129info.binaryName = parts[i+3]130info.binaryDirectory = "/".join(parts[i+1:i+3])131info.binaryPath = os.path.join(info.binaryDirectory, info.binaryName)132info.version = parts[i+2]134info.deployedInstallName = f"@executable_path/../Frameworks/{os.path.join(info.frameworkName, info.binaryPath)}"135info.destinationDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, info.binaryDirectory)137info.sourceResourcesDirectory = os.path.join(info.frameworkPath, "Resources")138info.sourceContentsDirectory = os.path.join(info.frameworkPath, "Contents")139info.sourceVersionContentsDirectory = os.path.join(info.frameworkPath, "Versions", info.version, "Contents")140info.destinationResourcesDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Resources")141info.destinationVersionContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Versions", info.version, "Contents")143return info145class ApplicationBundleInfo(object):146def __init__(self, path: str):147self.path = path148# for backwards compatibility reasons, this must remain as Bitcoin-Qt149self.binaryPath = os.path.join(path, "Contents", "MacOS", "Bitcoin-Qt")150if not os.path.exists(self.binaryPath):151raise RuntimeError(f"Could not find bundle binary for {path}")152self.resourcesPath = os.path.join(path, "Contents", "Resources")153self.pluginPath = os.path.join(path, "Contents", "PlugIns")155class DeploymentInfo(object):156def __init__(self):157self.qtPath = None158self.pluginPath = None159self.deployedFrameworks = []161def detectQtPath(self, frameworkDirectory: str):162parentDir = os.path.dirname(frameworkDirectory)163if os.path.exists(os.path.join(parentDir, "share", "qt", "plugins")):164self.qtPath = parentDir165else:166self.qtPath = os.getenv("QTDIR", None)168if self.qtPath is not None:169pluginPath = os.path.join(self.qtPath, "share", "qt", "plugins")170if os.path.exists(pluginPath):171self.pluginPath = pluginPath173def usesFramework(self, name: str) -> bool:174for framework in self.deployedFrameworks:175if framework.endswith(".framework"):176if framework.startswith(f"{name}."):177return True178elif framework.endswith(".dylib"):179if framework.startswith(f"lib{name}."):180return True181return False183def getFrameworks(binaryPath: str, verbose: int, rpath: str = '') -> list[FrameworkInfo]:184objdump = os.getenv("OBJDUMP", "objdump")185if verbose:186print(f"Inspecting with {objdump}: {binaryPath}")187output = run([objdump, "--macho", "--dylibs-used", binaryPath], stdout=PIPE, stderr=PIPE, text=True)188if output.returncode != 0:189sys.stderr.write(output.stderr)190sys.stderr.flush()191raise RuntimeError(f"{objdump} failed with return code {output.returncode}")193lines = output.stdout.split("\n")194lines.pop(0) # First line is the inspected binary195if ".framework" in binaryPath or binaryPath.endswith(".dylib"):196lines.pop(0) # Frameworks and dylibs list themselves as a dependency.198libraries = []199for line in lines:200line = line.replace("@loader_path", os.path.dirname(binaryPath))201if rpath:202line = line.replace("@rpath", rpath)203info = FrameworkInfo.fromLibraryLine(line.strip())204if info is not None:205if verbose:206print("Found framework:")207print(info)208libraries.append(info)210return libraries212def runInstallNameTool(action: str, *args):213installnametoolbin=os.getenv("INSTALL_NAME_TOOL", "install_name_tool")214run([installnametoolbin, "-"+action] + list(args), check=True)216def changeInstallName(oldName: str, newName: str, binaryPath: str, verbose: int):217if verbose:218print("Using install_name_tool:")219print(" in", binaryPath)220print(" change reference", oldName)221print(" to", newName)222runInstallNameTool("change", oldName, newName, binaryPath)224def changeIdentification(id: str, binaryPath: str, verbose: int):225if verbose:226print("Using install_name_tool:")227print(" change identification in", binaryPath)228print(" to", id)229runInstallNameTool("id", id, binaryPath)231def runStrip(binaryPath: str, verbose: int):232stripbin=os.getenv("STRIP", "strip")233if verbose:234print("Using strip:")235print(" stripped", binaryPath)236run([stripbin, "-x", binaryPath], check=True)238def copyFramework(framework: FrameworkInfo, path: str, verbose: int) -> Optional[str]:239if framework.sourceFilePath.startswith("Qt"):240#standard place for Nokia Qt installer's frameworks241fromPath = f"/Library/Frameworks/{framework.sourceFilePath}"242else:243fromPath = framework.sourceFilePath244toDir = os.path.join(path, framework.destinationDirectory)245toPath = os.path.join(toDir, framework.binaryName)247if framework.isDylib():248if not os.path.exists(fromPath):249raise RuntimeError(f"No file at {fromPath}")
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.