Skip to content

Commit eed65a8

Browse files
committed
adapter loader to new ogdf packaging
1 parent f487b2c commit eed65a8

File tree

2 files changed

+107
-56
lines changed

2 files changed

+107
-56
lines changed

src/ogdf_python/info.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from ogdf_python.loader import *
22

3-
__all__ = ["get_ogdf_info", "get_macro", "get_library_path", "get_include_path", "get_ogdf_include_path"]
3+
__all__ = ["get_ogdf_info", "get_macro"]
44

55

66
def get_macro(m):
@@ -31,35 +31,13 @@ def conf_which(n):
3131
return getattr(cppyy.gbl.conf_which, w)().decode("ascii")
3232

3333

34-
def get_library_path(name=None):
35-
if name is None:
36-
return get_library_path("OGDF") or get_library_path("libOGDF")
37-
return cppyy.gbl.gSystem.FindDynamicLibrary(cppyy.gbl.CppyyLegacy.TString(name), True)
38-
39-
40-
def get_ogdf_include_path():
41-
include = "ogdf/basic/Graph.h"
42-
path = get_include_path(include)
43-
if path:
44-
path = path.removesuffix(include)
45-
return path
46-
47-
48-
def get_include_path(name="ogdf/basic/Graph.h"):
49-
import ctypes
50-
s = ctypes.c_char_p()
51-
if cppyy.gbl.gSystem.IsFileInIncludePath(name, s):
52-
return s.value.decode()
53-
else:
54-
return None
55-
56-
5734
def get_ogdf_info():
5835
from ogdf_python import __version__
5936
cppinclude("ogdf/basic/System.h")
6037
data = {
61-
"ogdf_path": get_library_path() or "unknown",
62-
"ogdf_include_path": get_ogdf_include_path() or "unknown",
38+
"ogdf_path": get_loaded_library_path() or "unknown",
39+
"ogdf_include_path": get_base_include_path() or "unknown",
40+
"ogdf_config_include_path": get_base_include_path("ogdf/basic/internal/config_autogen.h") or "unknown",
6341
"ogdf_version": get_macro("OGDF_VERSION").strip('"'),
6442
"ogdf_python_version": __version__,
6543
"ogdf_debug": get_macro("OGDF_DEBUG") is not None,

src/ogdf_python/loader.py

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import os
22
import platform
3+
import warnings
4+
from pathlib import Path
35

46
import importlib_resources
57
import sys
@@ -27,60 +29,131 @@
2729
raise
2830

2931
cppyy.ll.set_signals_as_exception(True)
30-
cppyy.add_include_path(os.path.dirname(os.path.realpath(__file__)))
32+
CONFIG = os.getenv("OGDF_PYTHON_MODE", "release")
33+
if CONFIG not in ("release", "debug"):
34+
warnings.warn(f"Environment variable OGDF_PYTHON_MODE set to '{CONFIG}' instead of 'debug' or 'release'.")
35+
36+
37+
## Search Utils
38+
39+
def get_library_path(name=None):
40+
if name is None:
41+
if CONFIG == "release":
42+
return get_library_path("OGDF") or get_library_path("libOGDF")
43+
else:
44+
return get_library_path(f"OGDF-{CONFIG}") or get_library_path(f"libOGDF-{CONFIG}")
45+
return cppyy.gbl.gSystem.FindDynamicLibrary(cppyy.gbl.CppyyLegacy.TString(name), True)
46+
47+
48+
def get_loaded_library_path(name="OGDF"):
49+
from pathlib import Path
50+
return [s for s in cppyy.gbl.gSystem.GetLibraries().split(" ") if name in Path(s).name]
51+
52+
53+
def get_base_include_path(include="ogdf/basic/Graph.h"):
54+
path = get_include_path(include)
55+
if path:
56+
path = path.removesuffix(include)
57+
return path
58+
59+
60+
def get_include_path(name="ogdf/basic/Graph.h"):
61+
import ctypes
62+
s = ctypes.c_char_p()
63+
if cppyy.gbl.gSystem.IsFileInIncludePath(name, s):
64+
return s.value.decode()
65+
else:
66+
return None
67+
68+
69+
def call_if_exists(func, path):
70+
if Path(path).is_dir():
71+
func(str(path))
72+
return True
73+
return False
74+
75+
76+
## Setup Search Paths
3177

3278
if "OGDF_INSTALL_DIR" in os.environ:
33-
INSTALL_DIR = os.path.expanduser(os.getenv("OGDF_INSTALL_DIR"))
34-
cppyy.add_include_path(os.path.join(INSTALL_DIR, "include"))
35-
cppyy.add_library_path(os.path.join(INSTALL_DIR, "lib")) # TODO windows?
79+
INSTALL_DIR = Path(os.getenv("OGDF_INSTALL_DIR")).absolute()
80+
if call_if_exists(cppyy.add_library_path, INSTALL_DIR / "lib64"):
81+
call_if_exists(cppyy.add_library_path, INSTALL_DIR / "lib")
82+
else:
83+
cppyy.add_library_path(str(INSTALL_DIR / "lib"))
84+
cppyy.add_include_path(str(INSTALL_DIR / "include"))
85+
3686
if "OGDF_BUILD_DIR" in os.environ:
37-
BUILD_DIR = os.path.expanduser(os.getenv("OGDF_BUILD_DIR"))
38-
cppyy.add_include_path(os.path.join(BUILD_DIR, "include"))
39-
cppyy.add_include_path(os.path.join(BUILD_DIR, "..", "include")) # TODO not canonical
40-
cppyy.add_library_path(BUILD_DIR)
87+
BUILD_DIR = Path(os.getenv("OGDF_BUILD_DIR")).absolute()
88+
cppyy.add_library_path(str(BUILD_DIR))
89+
call_if_exists(cppyy.add_library_path, BUILD_DIR / "Debug")
90+
call_if_exists(cppyy.add_library_path, BUILD_DIR / "Release")
91+
cppyy.add_include_path(str(BUILD_DIR / "include"))
92+
for line in open(BUILD_DIR / "CMakeCache.txt"):
93+
line = line.strip()
94+
if line.startswith("OGDF-PROJECT_SOURCE_DIR"):
95+
key, _, val = line.partition("=")
96+
cppyy.add_include_path(str(Path(val) / "include"))
97+
4198
try:
4299
wheel_inst_dir = importlib_resources.files("ogdf_wheel") / "install"
43100
if wheel_inst_dir.is_dir():
44101
cppyy.add_library_path(str(wheel_inst_dir / "lib"))
45-
cppyy.add_library_path(str(wheel_inst_dir / "bin"))
46102
cppyy.add_include_path(str(wheel_inst_dir / "include"))
47103
except ImportError:
48104
pass
49105

106+
## Now do the actual loading
107+
50108
cppyy.cppdef("#undef NDEBUG")
109+
if CONFIG == "release":
110+
cppyy.cppdef("#define NDEBUG")
111+
cppyy.include("cassert")
51112
cppyy.cppdef("#define OGDF_INSTALL")
113+
52114
try:
53-
cppyy.load_library("OGDF")
115+
if CONFIG == "release":
116+
cppyy.load_library("COIN")
117+
cppyy.load_library("OGDF")
118+
else:
119+
cppyy.load_library(f"COIN-{CONFIG}")
120+
cppyy.load_library(f"OGDF-{CONFIG}")
121+
122+
config_autogen_h = "ogdf/basic/internal/config_autogen.h"
123+
if not get_include_path(config_autogen_h):
124+
# try to find the config-dependent header include path if it isn't correctly configured yet
125+
config_include = get_include_path(f"ogdf-{CONFIG}/{config_autogen_h}")
126+
if config_include:
127+
config_include = config_include.removesuffix(config_autogen_h)
128+
cppyy.add_include_path(config_include)
129+
cppyy.include(config_autogen_h)
54130

55-
cppyy.include("ogdf/basic/internal/config_autogen.h")
56131
cppyy.include("ogdf/basic/internal/config.h")
57132
cppyy.include("ogdf/basic/Graph.h")
58-
try:
59-
cppyy.include("ogdf/cluster/ClusterGraphObserver.h") # otherwise only pre-declared
60-
except ImportError:
61-
pass # gone in newer versions
62133
cppyy.include("ogdf/fileformats/GraphIO.h")
63134
cppyy.include("ogdf/basic/LayoutStandards.h")
64-
except:
65-
print( # TODO check if the issue is really that the file couldn't be found
66-
"ogdf-python couldn't load OGDF. "
135+
except (RuntimeError, ImportError) as e:
136+
raise ImportError(
137+
f"ogdf-python couldn't load OGDF in mode '{CONFIG}'.\n"
138+
"Please check the above underlying error and check that the below search paths contain "
139+
"OGDF headers and shared libraries in the correct release/debug configuration.\n"
67140
"If you haven't installed OGDF globally to your system, "
68-
"please set environment variables OGDF_INSTALL_DIR or OGDF_BUILD_DIR. "
69-
"The current search path is:\n%s\n"
70-
"The current include path is:\n%s\n" %
71-
(cppyy.gbl.gSystem.GetDynamicPath(), cppyy.gbl.gInterpreter.GetIncludePath()),
72-
file=sys.stderr)
73-
raise
141+
"you can use the environment variables OGDF_INSTALL_DIR or OGDF_BUILD_DIR.\n"
142+
f"The current search path is:\n{cppyy.gbl.gSystem.GetDynamicPath()}\n"
143+
f"The current include path is:\n{cppyy.gbl.gInterpreter.GetIncludePath()}\n"
144+
) from e
74145

75-
if cppyy.gbl.ogdf.debugMode:
76-
cppyy.cppdef("#undef NDEBUG")
146+
if CONFIG == "release":
147+
if cppyy.gbl.ogdf.debugMode:
148+
warnings.warn("Attempted to load OGDF release build, but the found library was built in debug mode.")
77149
else:
78-
cppyy.cppdef("#define NDEBUG")
79-
cppyy.include("cassert")
150+
if not cppyy.gbl.ogdf.debugMode:
151+
warnings.warn("Attempted to load OGDF debug build, but the found library was built in release mode.")
80152

81-
# Load re-exports
153+
## Load re-exports
82154
from cppyy import include as cppinclude, cppdef, cppexec, nullptr
83155
from cppyy.gbl import ogdf
84156

85-
__all__ = ["cppyy", "cppinclude", "cppdef", "cppexec", "nullptr", "ogdf"]
157+
__all__ = ["cppyy", "cppinclude", "cppdef", "cppexec", "nullptr", "ogdf",
158+
"get_library_path", "get_loaded_library_path", "get_include_path", "get_base_include_path"]
86159
__keep_imports = [cppyy, cppinclude, cppdef, cppexec, nullptr, ogdf]

0 commit comments

Comments
 (0)