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.
251if os.path.exists(toPath):252return None # Already there254if not os.path.exists(toDir):255os.makedirs(toDir)257shutil.copy2(fromPath, toPath)258if verbose:259print("Copied:", fromPath)260print(" to:", toPath)261else:262to_dir = os.path.join(path, "Contents", "Frameworks", framework.frameworkName)263if os.path.exists(to_dir):264return None # Already there266from_dir = framework.frameworkPath267if not os.path.exists(from_dir):268raise RuntimeError(f"No directory at {from_dir}")270shutil.copytree(from_dir, to_dir, symlinks=True)271if verbose:272print("Copied:", from_dir)273print(" to:", to_dir)275headers_link = os.path.join(to_dir, "Headers")276if os.path.exists(headers_link):277os.unlink(headers_link)279headers_dir = os.path.join(to_dir, framework.binaryDirectory, "Headers")280if os.path.exists(headers_dir):281shutil.rmtree(headers_dir)283permissions = os.stat(toPath)284if not permissions.st_mode & stat.S_IWRITE:285os.chmod(toPath, permissions.st_mode | stat.S_IWRITE)287return toPath289def deployFrameworks(frameworks: list[FrameworkInfo], bundlePath: str, binaryPath: str, strip: bool, verbose: int, deploymentInfo: Optional[DeploymentInfo] = None) -> DeploymentInfo:290if deploymentInfo is None:291deploymentInfo = DeploymentInfo()293while len(frameworks) > 0:294framework = frameworks.pop(0)295deploymentInfo.deployedFrameworks.append(framework.frameworkName)297print("Processing", framework.frameworkName, "...")299# Get the Qt path from one of the Qt frameworks300if deploymentInfo.qtPath is None and framework.isQtFramework():301deploymentInfo.detectQtPath(framework.frameworkDirectory)303if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath):304print(framework.frameworkName, "already deployed, skipping.")305continue307# install_name_tool the new id into the binary308changeInstallName(framework.installName, framework.deployedInstallName, binaryPath, verbose)310# Copy framework to app bundle.311deployedBinaryPath = copyFramework(framework, bundlePath, verbose)312# Skip the rest if already was deployed.313if deployedBinaryPath is None:314continue316if strip:317runStrip(deployedBinaryPath, verbose)319# install_name_tool it a new id.320changeIdentification(framework.deployedInstallName, deployedBinaryPath, verbose)321# Check for framework dependencies322dependencies = getFrameworks(deployedBinaryPath, verbose, rpath=framework.frameworkDirectory)324for dependency in dependencies:325changeInstallName(dependency.installName, dependency.deployedInstallName, deployedBinaryPath, verbose)327# Deploy framework if necessary.328if dependency.frameworkName not in deploymentInfo.deployedFrameworks and dependency not in frameworks:329frameworks.append(dependency)331return deploymentInfo333def deployFrameworksForAppBundle(applicationBundle: ApplicationBundleInfo, strip: bool, verbose: int) -> DeploymentInfo:334frameworks = getFrameworks(applicationBundle.binaryPath, verbose)335if len(frameworks) == 0:336print(f"Warning: Could not find any external frameworks to deploy in {applicationBundle.path}.")337return DeploymentInfo()338else:339return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose)341def deployPlugins(appBundleInfo: ApplicationBundleInfo, deploymentInfo: DeploymentInfo, strip: bool, verbose: int):342plugins = []343if deploymentInfo.pluginPath is None:344return345for dirpath, dirnames, filenames in os.walk(deploymentInfo.pluginPath):346pluginDirectory = os.path.relpath(dirpath, deploymentInfo.pluginPath)348if pluginDirectory not in ['styles', 'platforms']:349continue351for pluginName in filenames:352pluginPath = os.path.join(pluginDirectory, pluginName)354if pluginName.split('.')[0] not in ['libqminimal', 'libqcocoa', 'libqmacstyle']:355continue357plugins.append((pluginDirectory, pluginName))359for pluginDirectory, pluginName in plugins:360print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...")362sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName)363destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory)364if not os.path.exists(destinationDirectory):365os.makedirs(destinationDirectory)367destinationPath = os.path.join(destinationDirectory, pluginName)368shutil.copy2(sourcePath, destinationPath)369if verbose:370print("Copied:", sourcePath)371print(" to:", destinationPath)373if strip:374runStrip(destinationPath, verbose)376dependencies = getFrameworks(destinationPath, verbose)378for dependency in dependencies:379changeInstallName(dependency.installName, dependency.deployedInstallName, destinationPath, verbose)381# Deploy framework if necessary.382if dependency.frameworkName not in deploymentInfo.deployedFrameworks:383deployFrameworks([dependency], appBundleInfo.path, destinationPath, strip, verbose, deploymentInfo)385ap = ArgumentParser(description="""Improved version of macdeployqt.387Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .zip file.388Note, that the "dist" folder will be deleted before deploying on each run.390Optionally, Qt translation files (.qm) can be added to the bundle.""")392ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")393ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information")394ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")395ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")396ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.")397ap.add_argument("-zip", nargs=1, metavar="zip", help="create a .zip containing the app bundle")399config = ap.parse_args()401verbose = config.verbose403# ------------------------------------------------405app_bundle = config.app_bundle[0]407if not os.path.exists(app_bundle):408sys.stderr.write(f"Error: Could not find app bundle \"{app_bundle}\"\n")409sys.exit(1)411# ------------------------------------------------413if os.path.exists("dist"):414print("+ Removing existing dist folder +")415shutil.rmtree("dist")417# ------------------------------------------------419target = os.path.join("dist", "Bitcoin-Qt.app")421print("+ Copying source bundle +")422if verbose:423print(app_bundle, "->", target)425os.mkdir("dist")426shutil.copytree(app_bundle, target, symlinks=True)428applicationBundle = ApplicationBundleInfo(target)430# ------------------------------------------------432print("+ Deploying frameworks +")434try:435deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose)436if deploymentInfo.qtPath is None:437deploymentInfo.qtPath = os.getenv("QTDIR", None)438if deploymentInfo.qtPath is None:439sys.stderr.write("Warning: Could not detect Qt's path, skipping plugin deployment!\n")440config.plugins = False441except RuntimeError as e:442sys.stderr.write(f"Error: {str(e)}\n")443sys.exit(1)445# ------------------------------------------------447if config.plugins:448print("+ Deploying plugins +")450try:451deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose)452except RuntimeError as e:453sys.stderr.write(f"Error: {str(e)}\n")454sys.exit(1)456# ------------------------------------------------458if config.translations_dir:459if not Path(config.translations_dir[0]).exists():460sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n")461sys.exit(1)463print("+ Adding Qt translations +")465translations = Path(config.translations_dir[0])467regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)')469lang_files = [x for x in translations.iterdir() if regex.match(x.name)]471for file in lang_files:472if verbose:473print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name))474shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name))476# ------------------------------------------------478print("+ Installing qt.conf +")480qt_conf="""[Paths]481Translations=Resources482Plugins=PlugIns483"""485with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f:486f.write(qt_conf.encode())488# ------------------------------------------------490if platform.system() == "Darwin":491# The earlier strip and install_name_tool calls invalidated existing framework492# and plugin code signatures.493print("+ Signing app bundle +")494sign_targets = [495path496for pattern in ("Frameworks/*", "PlugIns/*/*")497for path in Path(target, "Contents").glob(pattern)498if path.is_file() or path.name.endswith(".framework")499]500# Sign the app bundle last
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.