Skip to content

Commit

Permalink
Deprecate codefile_type and is_codefile
Browse files Browse the repository at this point in the history
  • Loading branch information
kenodegard committed Oct 18, 2023
1 parent bb4668d commit 1dc2470
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 101 deletions.
11 changes: 3 additions & 8 deletions conda_build/os_utils/ldd.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@

from conda_build.conda_interface import linked_data, untracked
from conda_build.os_utils.macho import otool
from conda_build.os_utils.pyldd import (
codefile_class,
inspect_linkages,
is_codefile,
machofile,
)
from conda_build.os_utils.pyldd import codefile_class, inspect_linkages, machofile

LDD_RE = re.compile(r"\s*(.*?)\s*=>\s*(.*?)\s*\(.*\)")
LDD_NOT_FOUND_RE = re.compile(r"\s*(.*?)\s*=>\s*not found")
Expand Down Expand Up @@ -118,7 +113,7 @@ def get_package_obj_files(dist, prefix):
files = get_package_files(dist, prefix)
for f in files:
path = join(prefix, f)
if is_codefile(path):
if codefile_class(path):
res.append(f)

return res
Expand All @@ -130,7 +125,7 @@ def get_untracked_obj_files(prefix):
files = untracked(prefix)
for f in files:
path = join(prefix, f)
if is_codefile(path):
if codefile_class(path):
res.append(f)

return res
78 changes: 40 additions & 38 deletions conda_build/os_utils/liefldd.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
# Copyright (C) 2014 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
try:
from collections.abc import Hashable
except ImportError:
from collections.abc import Hashable
from __future__ import annotations

import hashlib
import json
import os
import struct
import sys
import threading
from collections.abc import Hashable
from fnmatch import fnmatch
from functools import partial
from pathlib import Path
from subprocess import PIPE, Popen

from ..deprecations import deprecated
from .external import find_executable
from .pyldd import DLLfile, EXEfile, elffile, machofile

# lief cannot handle files it doesn't know about gracefully
# TODO :: Remove all use of pyldd
# Currently we verify the output of each against the other
from .pyldd import codefile_type as codefile_type_pyldd
from .pyldd import inspect_linkages as inspect_linkages_pyldd

codefile_type = codefile_type_pyldd
have_lief = False
try:
import lief

lief.logging.disable()
have_lief = True
except:
pass
except ImportError:
have_lief = False


@deprecated("3.28.0", "4.0.0", addendum="Use `isinstance(value, str)` instead.")
Expand All @@ -45,17 +42,16 @@ def is_string(s):
# these are to be avoided, or if not avoided they
# should be passed a binary when possible as that
# will prevent having to parse it multiple times.
def ensure_binary(file):
if not isinstance(file, str):
def ensure_binary(file: str | os.PathLike | Path | lief.Binary) -> lief.Binary | None:
if isinstance(file, lief.Binary):
return file
else:
try:
if not os.path.exists(file):
return []
return lief.parse(file)
except:
print(f"WARNING: liefldd: failed to ensure_binary({file})")
return None
elif not Path(file).exists():
return None
try:
return lief.parse(str(file))
except BaseException:
print(f"WARNING: liefldd: failed to ensure_binary({file})")
return None


def nm(filename):
Expand All @@ -76,25 +72,31 @@ def nm(filename):
print("No symbols found")


def codefile_type_liefldd(file, skip_symlinks=True):
binary = ensure_binary(file)
result = None
if binary:
if binary.format == lief.EXE_FORMATS.PE:
if lief.PE.DLL_CHARACTERISTICS:
if binary.header.characteristics & lief.PE.HEADER_CHARACTERISTICS.DLL:
result = "DLLfile"
else:
result = "EXEfile"
if have_lief:

def codefile_class(
path: str | os.PathLike | Path,
skip_symlinks: bool = False,
) -> type[DLLfile | EXEfile | machofile | elffile] | None:
# same signature as conda.os_utils.pyldd.codefile_class
if not (binary := ensure_binary(path)):
return None
elif (
binary.format == lief.EXE_FORMATS.PE
and lief.PE.HEADER_CHARACTERISTICS.DLL in binary.header.characteristics_list
):
return DLLfile
elif binary.format == lief.EXE_FORMATS.PE:
return EXEfile
elif binary.format == lief.EXE_FORMATS.MACHO:
result = "machofile"
return machofile
elif binary.format == lief.EXE_FORMATS.ELF:
result = "elffile"
return result

return elffile
else:
return None

if have_lief:
codefile_type = codefile_type_liefldd
else:
from .pyldd import codefile_class


def _trim_sysroot(sysroot):
Expand Down Expand Up @@ -506,7 +508,7 @@ def inspect_linkages_lief(
while tmp_filename:
if (
not parent_exe_dirname
and codefile_type(tmp_filename) == "EXEfile"
and codefile_class(tmp_filename) == EXEfile
):
parent_exe_dirname = os.path.dirname(tmp_filename)
tmp_filename = parents_by_filename[tmp_filename]
Expand Down Expand Up @@ -596,7 +598,7 @@ def get_linkages(
result_pyldd = []
debug = False
if not have_lief or debug:
if codefile_type(filename) not in ("DLLfile", "EXEfile"):
if codefile_class(filename) not in (DLLfile, EXEfile):
result_pyldd = inspect_linkages_pyldd(
filename,
resolve_filenames=resolve_filenames,
Expand All @@ -608,7 +610,7 @@ def get_linkages(
return result_pyldd
else:
print(
f"WARNING: failed to get_linkages, codefile_type('{filename}')={codefile_type(filename)}"
f"WARNING: failed to get_linkages, codefile_class('{filename}')={codefile_class(filename)}"
)
return {}
result_lief = inspect_linkages_lief(
Expand Down
59 changes: 37 additions & 22 deletions conda_build/os_utils/pyldd.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,40 +1033,55 @@ def codefile(file, arch="any", initial_rpaths_transitive=[]):
return inscrutablefile(file, list(initial_rpaths_transitive))


def codefile_class(filename, skip_symlinks=False):
if os.path.islink(filename):
if skip_symlinks:
return None
else:
filename = os.path.realpath(filename)
if os.path.isdir(filename):
def codefile_class(
path: str | os.PathLike | Path,
skip_symlinks: bool = False,
) -> type[DLLfile | EXEfile | machofile | elffile] | None:
# same signature as conda.os_utils.liefldd.codefile_class
path = Path(path)
if skip_symlinks and path.is_symlink():
return None
if filename.endswith((".dll", ".pyd")):
path = path.resolve()

def _get_magic_bit(path: Path) -> bytes:
with path.open("rb") as handle:
bit = handle.read(4)
return struct.unpack(BIG_ENDIAN + "L", bit)[0]

if path.is_dir():
return None
elif path.suffix.lower() in (".dll", ".pyd"):
return DLLfile
if filename.endswith(".exe"):
elif path.suffix.lower() == ".exe":
return EXEfile
# Java .class files share 0xCAFEBABE with Mach-O FAT_MAGIC.
if filename.endswith(".class"):
elif path.suffix.lower() == ".class":
# Java .class files share 0xCAFEBABE with Mach-O FAT_MAGIC.
return None
if not os.path.exists(filename) or os.path.getsize(filename) < 4:
elif not path.exists() or path.stat().st_size < 4:
return None
elif (magic := _get_magic_bit(path)) == ELF_HDR:
return elffile
elif magic in (FAT_MAGIC, MH_MAGIC, MH_CIGAM, MH_CIGAM_64):
return machofile
else:
return None
with open(filename, "rb") as file:
(magic,) = struct.unpack(BIG_ENDIAN + "L", file.read(4))
file.seek(0)
if magic in (FAT_MAGIC, MH_MAGIC, MH_CIGAM, MH_CIGAM_64):
return machofile
elif magic == ELF_HDR:
return elffile
return None


@deprecated.argument("3.28.0", "4.0.0", "filename", rename="path")
@deprecated(
"3.28.0",
"4.0.0",
addendum="Use `conda_build.os_utils.pyldd.codefile_class` instead.",
)
def is_codefile(path: str | os.PathLike | Path, skip_symlinks: bool = True) -> bool:
return bool(codefile_class(path, skip_symlinks=skip_symlinks))


@deprecated(
"3.28.0",
"4.0.0",
addendum="Use `conda_build.os_utils.pyldd.codefile_class` instead.",
)
def codefile_type(filename, skip_symlinks=True):
"Returns None, 'machofile' or 'elffile'"
klass = codefile_class(filename, skip_symlinks=skip_symlinks)
if not klass:
return None
Expand Down
Loading

0 comments on commit 1dc2470

Please sign in to comment.