Exemple #1
0
def detectDLLsWithDependencyWalker(binary_filename, scan_dirs):
    dwp_filename = binary_filename + ".dwp"
    output_filename = binary_filename + ".depends"

    # User query should only happen once if at all.
    with withFileLock(
        "Finding out dependency walker path and creating DWP file for %s"
        % binary_filename
    ):
        depends_exe = getDependsExePath()

        # Note: Do this under lock to avoid forked processes to hold
        # a copy of the file handle on Windows.
        putTextFileContents(
            dwp_filename,
            contents="""\
%(scan_dirs)s
SxS
"""
            % {
                "scan_dirs": "\n".join(
                    "UserDir %s" % getExternalUsePath(dirname) for dirname in scan_dirs
                )
            },
        )

    # Starting the process while locked, so file handles are not duplicated.
    # TODO: At least exit code should be checked, output goes to a filename,
    # but errors might be interesting potentially.

    _stdout, _stderr, _exit_code = executeProcess(
        command=(
            depends_exe,
            "-c",
            "-ot%s" % output_filename,
            "-d:%s" % dwp_filename,
            "-f1",
            "-pa1",
            "-ps1",
            binary_filename,
        ),
        external_cwd=True,
    )

    if not os.path.exists(output_filename):
        inclusion_logger.sysexit(
            "Error, 'depends.exe' failed to produce expected output."
        )

    # Opening the result under lock, so it is not getting locked by new processes.

    # Note: Do this under lock to avoid forked processes to hold
    # a copy of the file handle on Windows.
    result = parseDependsExeOutput(output_filename)

    deleteFile(output_filename, must_exist=True)
    deleteFile(dwp_filename, must_exist=True)

    return result
Exemple #2
0
def detectDLLsWithDependencyWalker(binary_filename, scan_dirs):
    dwp_filename = binary_filename + ".dwp"
    output_filename = binary_filename + ".depends"

    # User query should only happen once if at all.
    with withFileLock(
            "Finding out dependency walker path and creating DWP file for %s" %
            binary_filename):
        depends_exe = getDependsExePath()

        # Note: Do this under lock to avoid forked processes to hold
        # a copy of the file handle on Windows.
        with open(dwp_filename, "w") as dwp_file:
            dwp_file.write(
                """\
%(scan_dirs)s
SxS
""" % {
                    "scan_dirs":
                    "\n".join("UserDir %s" % getExternalUsePath(dirname)
                              for dirname in scan_dirs)
                })

    # Starting the process while locked, so file handles are not duplicated.
    depends_exe_process = subprocess.Popen(
        (
            depends_exe,
            "-c",
            "-ot%s" % output_filename,
            "-d:%s" % dwp_filename,
            "-f1",
            "-pa1",
            "-ps1",
            binary_filename,
        ),
        stdin=getNullInput(),
        cwd=getExternalUsePath(os.getcwd()),
    )

    # TODO: Exit code should be checked.
    depends_exe_process.wait()

    if not os.path.exists(output_filename):
        inclusion_logger.sysexit(
            "Error, depends.exe failed to produce expected output.")

    # Opening the result under lock, so it is not getting locked by new processes.

    # Note: Do this under lock to avoid forked processes to hold
    # a copy of the file handle on Windows.
    result = _parseDependsExeOutput(output_filename)

    deleteFile(output_filename, must_exist=True)
    deleteFile(dwp_filename, must_exist=True)

    return result
Exemple #3
0
def _fixupBinaryDLLPathsMacOS(binary_filename, package_name, dll_map,
                              duplicate_dlls, original_location):
    """For macOS, the binary needs to be told to use relative DLL paths"""

    # There may be nothing to do, in case there are no DLLs.
    if not dll_map:
        return

    had_self, rpath_map = _detectBinaryPathDLLsMacOS(
        original_dir=os.path.dirname(original_location),
        binary_filename=original_location,
        package_name=package_name,
        keep_unresolved=True,
        recursive=False,
    )

    mapping = []

    for resolved_filename, rpath_filename in rpath_map.items():
        for (original_path, _package_name, dist_path) in dll_map:
            if resolved_filename == original_path:
                break

            # Might have been a removed duplicate, check those too.
            if original_path in duplicate_dlls.get(resolved_filename, ()):
                break

        else:
            dist_path = None

        if dist_path is None:
            inclusion_logger.sysexit("""\
Error, problem with dependency scan of '%s' with '%s' please report the bug."""
                                     % (binary_filename, rpath_filename))

        mapping.append((rpath_filename, "@executable_path/" + dist_path))

    if mapping or had_self:
        callInstallNameTool(
            filename=binary_filename,
            mapping=mapping,
            id_path=os.path.basename(binary_filename) if had_self else None,
            rpath=None,
        )
Exemple #4
0
def _resolveBinaryPathDLLsMacOS(original_dir, binary_filename, paths,
                                package_specific_dirs):
    had_self = False

    result = OrderedDict()

    rpaths = _detectBinaryRPathsMacOS(original_dir, binary_filename)
    rpaths.update(package_specific_dirs)

    for path in paths:
        if path.startswith("@rpath/"):
            # Resolve rpath to just the ones given, first match.
            for rpath in rpaths:
                if os.path.exists(os.path.join(rpath, path[7:])):
                    resolved_path = os.path.normpath(
                        os.path.join(rpath, path[7:]))
                    break
            else:
                # This is only a guess, might be missing package specific directories.
                resolved_path = os.path.join(original_dir, path[7:])
        elif path.startswith("@loader_path/"):
            resolved_path = os.path.join(original_dir, path[13:])
        elif os.path.basename(path) == os.path.basename(binary_filename):
            # We ignore the references to itself coming from the library id.
            continue
        else:
            resolved_path = path

        if not os.path.exists(resolved_path):
            inclusion_logger.sysexit(
                "Error, failed to resolve DLL path %s (for %s), please report the bug."
                % (path, binary_filename))

        # Some libraries depend on themselves.
        if areSamePaths(binary_filename, resolved_path):
            had_self = True
            continue

        result[resolved_path] = path

    return had_self, result
Exemple #5
0
def _createNodeTree(filename):
    """Create a node tree.

    Turn that source code into a node tree structure. If recursion into
    imported modules is available, more trees will be available during
    optimization, or immediately through recursed directory paths.

    """

    # Many cases to deal with, pylint: disable=too-many-branches

    # First, build the raw node tree from the source code.
    main_module = Building.buildMainModuleTree(
        filename=filename,
        is_main=not Options.shallMakeModule(),
    )

    # First remove old object files and old generated files, old binary or
    # module, and standalone mode program directory if any, they can only do
    # harm.
    source_dir = OutputDirectories.getSourceDirectoryPath()

    if not Options.shallOnlyExecCCompilerCall():
        SconsInterface.cleanSconsDirectory(source_dir)

    # Prepare the ".dist" directory, throwing away what was there before.
    if Options.isStandaloneMode():
        standalone_dir = OutputDirectories.getStandaloneDirectoryPath(bundle=False)
        removeDirectory(path=standalone_dir, ignore_errors=True)

        if Options.shallCreateAppBundle():
            removeDirectory(
                path=changeFilenameExtension(standalone_dir, ".app"), ignore_errors=True
            )

    # Delete result file, to avoid confusion with previous build and to
    # avoid locking issues after the build.
    deleteFile(
        path=OutputDirectories.getResultFullpath(onefile=False), must_exist=False
    )
    if Options.isOnefileMode():
        deleteFile(
            path=OutputDirectories.getResultFullpath(onefile=True), must_exist=False
        )

    # Second, do it for the directories given.
    for plugin_filename in Options.getShallFollowExtra():
        Recursion.checkPluginPath(plugin_filename=plugin_filename, module_package=None)

    for pattern in Options.getShallFollowExtraFilePatterns():
        Recursion.checkPluginFilenamePattern(pattern=pattern)

    for package_name in Options.getMustIncludePackages():
        package_name, package_directory, kind = Importing.locateModule(
            module_name=ModuleName(package_name),
            parent_package=None,
            level=0,
        )

        if kind != "absolute":
            inclusion_logger.sysexit(
                "Error, failed to locate package %r you asked to include."
                % package_name.asString()
            )

        Recursion.checkPluginPath(
            plugin_filename=package_directory,
            module_package=package_name.getPackageName(),
        )

    for module_name in Options.getMustIncludeModules():
        module_name, module_filename, kind = Importing.locateModule(
            module_name=ModuleName(module_name),
            parent_package=None,
            level=0,
        )

        if kind != "absolute":
            inclusion_logger.sysexit(
                "Error, failed to locate module '%s' you asked to include."
                % module_name.asString()
            )

        Recursion.checkPluginSinglePath(
            plugin_filename=module_filename, module_package=module_name.getPackageName()
        )

    # Allow plugins to add more modules based on the initial set being complete.
    Plugins.onModuleInitialSet()

    # Then optimize the tree and potentially recursed modules.
    optimizeModules(main_module.getOutputFilename())

    # Allow plugins to comment on final module set.
    Plugins.onModuleCompleteSet()

    if Options.isExperimental("check_xml_persistence"):
        for module in ModuleRegistry.getRootModules():
            if module.isMainModule():
                return module

        assert False
    else:
        # Main module might change behind our back, look it up again.
        return main_module