cgcpp 1.8.2__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cgcpp/__init__.py +113 -0
- cgcpp/__main__.py +69 -0
- cgcpp/build.py +74 -0
- cgcpp/lib_loader_python310.pyd +0 -0
- cgcpp/lib_loader_python311.pyd +0 -0
- cgcpp/lib_loader_python312.pyd +0 -0
- cgcpp/lib_loader_python39.pyd +0 -0
- cgcpp-1.8.2.dist-info/METADATA +71 -0
- cgcpp-1.8.2.dist-info/RECORD +11 -0
- cgcpp-1.8.2.dist-info/WHEEL +5 -0
- cgcpp-1.8.2.dist-info/top_level.txt +1 -0
cgcpp/__init__.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
(c) Andriy Babak 2021-2025
|
|
3
|
+
|
|
4
|
+
date: 31/05/2021
|
|
5
|
+
modified: 03/04/2025 12:10:58
|
|
6
|
+
|
|
7
|
+
Author: Andriy Babak
|
|
8
|
+
e-mail: ababak@gmail.com
|
|
9
|
+
------------------------------
|
|
10
|
+
description: CG C++ Support module
|
|
11
|
+
Containerized builds and runtime loading
|
|
12
|
+
------------------------------
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import importlib.metadata
|
|
16
|
+
import importlib.util
|
|
17
|
+
import inspect
|
|
18
|
+
import os
|
|
19
|
+
import platform
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
__version__ = importlib.metadata.version("cgcpp")
|
|
24
|
+
__copyright__ = "(c) Andriy Babak 2021-2025"
|
|
25
|
+
|
|
26
|
+
from . import build
|
|
27
|
+
|
|
28
|
+
lib_loader_name = "lib_loader"
|
|
29
|
+
lib_suffix = f"_python{sys.version_info.major}{sys.version_info.minor}"
|
|
30
|
+
lib_loader_path = Path(__file__).with_name(f"{lib_loader_name}{lib_suffix}.pyd")
|
|
31
|
+
|
|
32
|
+
spec = importlib.util.spec_from_file_location(lib_loader_name, lib_loader_path)
|
|
33
|
+
lib_loader = importlib.util.module_from_spec(spec)
|
|
34
|
+
spec.loader.exec_module(lib_loader)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_library_path(lib_path, extra_frames=0):
|
|
38
|
+
"""
|
|
39
|
+
Try to guess a full library path
|
|
40
|
+
"""
|
|
41
|
+
lib_path = Path(lib_path)
|
|
42
|
+
lib_dir = lib_path.parent
|
|
43
|
+
lib_name = os.path.basename(lib_path)
|
|
44
|
+
lib_name, lib_ext = os.path.splitext(lib_path.name)
|
|
45
|
+
local_platform = platform.system().lower()
|
|
46
|
+
if local_platform == "windows":
|
|
47
|
+
lib_ext = ".dll"
|
|
48
|
+
elif local_platform == "linux":
|
|
49
|
+
lib_ext = ".so"
|
|
50
|
+
else:
|
|
51
|
+
raise EnvironmentError(f"Unsupported platform: {local_platform}")
|
|
52
|
+
if not os.path.dirname(lib_path):
|
|
53
|
+
# get call stack frames
|
|
54
|
+
frames = inspect.stack(0)
|
|
55
|
+
frame = 1 + extra_frames
|
|
56
|
+
# should be the third frame
|
|
57
|
+
# 0: this function
|
|
58
|
+
# 1: this module"s "call" function
|
|
59
|
+
# 2: the caller
|
|
60
|
+
if len(frames) > frame:
|
|
61
|
+
path = frames[frame][1]
|
|
62
|
+
if path:
|
|
63
|
+
lib_dir = Path(path).parent
|
|
64
|
+
full_lib_path = lib_dir.absolute() / f"{lib_name}{lib_ext}"
|
|
65
|
+
variants = [f"{lib_name}{lib_ext}", f"{lib_name}{lib_suffix}{lib_ext}"]
|
|
66
|
+
# Try to guess the host application
|
|
67
|
+
try:
|
|
68
|
+
from maya import cmds
|
|
69
|
+
except ImportError:
|
|
70
|
+
pass
|
|
71
|
+
else:
|
|
72
|
+
# The host application is Maya
|
|
73
|
+
maya_version = cmds.about(v=True)
|
|
74
|
+
maya_suffix = f"_maya{maya_version}"
|
|
75
|
+
variants.append(f"{lib_name}{maya_suffix}{lib_ext}")
|
|
76
|
+
variants.append(f"{lib_name}{lib_suffix}{maya_suffix}{lib_ext}")
|
|
77
|
+
try:
|
|
78
|
+
import hou
|
|
79
|
+
from hou import nodes
|
|
80
|
+
except ImportError:
|
|
81
|
+
pass
|
|
82
|
+
else:
|
|
83
|
+
# The host application is Houdini
|
|
84
|
+
houdini_version = os.path.splitext(hou.applicationVersionString())[0]
|
|
85
|
+
houdini_suffix = f"_houdini{houdini_version}"
|
|
86
|
+
variants.append(f"{lib_name}{houdini_suffix}{lib_ext}")
|
|
87
|
+
variants.append(f"{lib_name}{lib_suffix}{houdini_suffix}{lib_ext}")
|
|
88
|
+
for name in variants:
|
|
89
|
+
full_lib_path = lib_dir.absolute() / name
|
|
90
|
+
if full_lib_path.is_file():
|
|
91
|
+
return full_lib_path
|
|
92
|
+
raise AttributeError(
|
|
93
|
+
f'Library not found: "{lib_dir.absolute().with_name(lib_name + lib_ext)}"'
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def call(*args, **kwargs):
|
|
98
|
+
"""
|
|
99
|
+
Call an external function from dynamically loaded library
|
|
100
|
+
Arguments:
|
|
101
|
+
lib (str) - full library path ("/some/lib/lib.so") or library name ("lib")
|
|
102
|
+
func (str) - function name
|
|
103
|
+
All the arguments get passed to an exported function from the library
|
|
104
|
+
Usage:
|
|
105
|
+
ret = cpp.call("some argument", some_named_argument=42, lib="/lib/path.so", func="custom")
|
|
106
|
+
"""
|
|
107
|
+
lib_path = kwargs.get("lib")
|
|
108
|
+
func_name = kwargs.get("func")
|
|
109
|
+
if not lib_path or not func_name:
|
|
110
|
+
raise AttributeError('Invalid usage. Expected arguments: "lib", "func"')
|
|
111
|
+
modified_kwargs = dict(kwargs)
|
|
112
|
+
modified_kwargs["lib"] = get_library_path(lib_path, extra_frames=1).as_posix()
|
|
113
|
+
return lib_loader.call(*args, **modified_kwargs)
|
cgcpp/__main__.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
(c) Andriy Babak 2021-2024
|
|
3
|
+
|
|
4
|
+
date: 01/06/2021
|
|
5
|
+
modified: 30/01/2025 14:12:22
|
|
6
|
+
|
|
7
|
+
Author: Andriy Babak
|
|
8
|
+
e-mail: ababak@gmail.com
|
|
9
|
+
------------------------------
|
|
10
|
+
description: CG C++ Support module
|
|
11
|
+
------------------------------
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from . import __copyright__, __version__, build
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
description="C++ module builder v{}".format(__version__),
|
|
24
|
+
epilog=__copyright__,
|
|
25
|
+
prog="python -m cgcpp",
|
|
26
|
+
)
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
"source", type=str, help="directory containing CMakeLists.txt to build"
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument("--out", help="output directory")
|
|
31
|
+
parser.add_argument("--build", help="build directory")
|
|
32
|
+
maya_default_directory = "C:/Program Files/Autodesk"
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--maya",
|
|
35
|
+
help='Autodesk directory with Maya installations. Default: "{}".'.format(
|
|
36
|
+
maya_default_directory
|
|
37
|
+
),
|
|
38
|
+
nargs="?",
|
|
39
|
+
const=maya_default_directory,
|
|
40
|
+
)
|
|
41
|
+
sidefx_default_directory = "C:/Program Files/Side Effects Software"
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"--houdini",
|
|
44
|
+
help='SideFX directory with Houdini installations. Default: "{}".'.format(
|
|
45
|
+
sidefx_default_directory
|
|
46
|
+
),
|
|
47
|
+
nargs="?",
|
|
48
|
+
const=sidefx_default_directory,
|
|
49
|
+
)
|
|
50
|
+
args, unknownargs = parser.parse_known_args()
|
|
51
|
+
source_dir = os.path.abspath(args.source).replace("\\", "/")
|
|
52
|
+
build_dir = args.build and os.path.abspath(args.build).replace("\\", "/")
|
|
53
|
+
out_dir = os.path.abspath(args.out or source_dir).replace("\\", "/")
|
|
54
|
+
if not os.path.isdir(args.source):
|
|
55
|
+
print('[ERROR] Directory does not exist: "{}"'.format(source_dir))
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
result = build.build(
|
|
58
|
+
source_dir=source_dir,
|
|
59
|
+
destination_dir=out_dir,
|
|
60
|
+
build_dir=build_dir,
|
|
61
|
+
maya_dir=args.maya,
|
|
62
|
+
houdini_dir=args.houdini,
|
|
63
|
+
)
|
|
64
|
+
if not result:
|
|
65
|
+
sys.exit(result)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
cgcpp/build.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
(c) Andriy Babak 2021-2024
|
|
3
|
+
|
|
4
|
+
date: 03/06/2021
|
|
5
|
+
modified: 30/05/2024 10:40:26
|
|
6
|
+
|
|
7
|
+
Author: Andriy Babak
|
|
8
|
+
e-mail: ababak@gmail.com
|
|
9
|
+
------------------------------
|
|
10
|
+
description: CG C++ Support module
|
|
11
|
+
------------------------------
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import subprocess
|
|
16
|
+
|
|
17
|
+
from . import __version__
|
|
18
|
+
|
|
19
|
+
DOCKER_APP = "docker"
|
|
20
|
+
DOCKER_IMAGE = "ababak/cgcpp:" + ".".join(__version__.split(".")[:2])
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def build(
|
|
24
|
+
source_dir,
|
|
25
|
+
destination_dir=None,
|
|
26
|
+
build_dir=None,
|
|
27
|
+
maya_dir=None,
|
|
28
|
+
houdini_dir=None,
|
|
29
|
+
):
|
|
30
|
+
"""Run docker image to build source directory."""
|
|
31
|
+
source_dir = os.path.abspath(source_dir).replace("\\", "/")
|
|
32
|
+
destination_dir = os.path.abspath(destination_dir or source_dir).replace("\\", "/")
|
|
33
|
+
try:
|
|
34
|
+
out = subprocess.check_output([DOCKER_APP, "images", "-q", DOCKER_IMAGE])
|
|
35
|
+
except OSError:
|
|
36
|
+
print("[ERROR] Docker not installed")
|
|
37
|
+
return 2
|
|
38
|
+
if not out:
|
|
39
|
+
print("[ERROR] Docker image is not available: {}".format(DOCKER_IMAGE))
|
|
40
|
+
print("Please reinstall cgcpp to rebuild it")
|
|
41
|
+
return 3
|
|
42
|
+
print('Source: "{}"'.format(source_dir))
|
|
43
|
+
print('Build: "{}"'.format(build_dir))
|
|
44
|
+
print('Output: "{}"'.format(destination_dir))
|
|
45
|
+
docker_args = [
|
|
46
|
+
DOCKER_APP,
|
|
47
|
+
"run",
|
|
48
|
+
"--rm",
|
|
49
|
+
"-v",
|
|
50
|
+
"{}:c:/source:ro".format(os.path.abspath(source_dir)),
|
|
51
|
+
"-v",
|
|
52
|
+
"{}:c:/out".format(os.path.abspath(destination_dir)),
|
|
53
|
+
]
|
|
54
|
+
if build_dir:
|
|
55
|
+
docker_args += ["-v", "{}:c:/build".format(os.path.abspath(build_dir))]
|
|
56
|
+
if maya_dir:
|
|
57
|
+
maya_dir = os.path.abspath(maya_dir).replace("\\", "/")
|
|
58
|
+
if not os.path.isdir(maya_dir):
|
|
59
|
+
print(
|
|
60
|
+
'[ERROR] Autodesk Maya directory does not exist: "{}"'.format(maya_dir)
|
|
61
|
+
)
|
|
62
|
+
return 1
|
|
63
|
+
docker_args += ["-v", maya_dir + ":c:/autodesk:ro"]
|
|
64
|
+
print('Autodesk Maya search directory: "{}"'.format(maya_dir))
|
|
65
|
+
if houdini_dir:
|
|
66
|
+
houdini_dir = os.path.abspath(houdini_dir).replace("\\", "/")
|
|
67
|
+
if not os.path.isdir(houdini_dir):
|
|
68
|
+
print('[ERROR] SideFX directory does not exist: "{}"'.format(houdini_dir))
|
|
69
|
+
return 1
|
|
70
|
+
docker_args += ["-v", houdini_dir + ":c:/sidefx:ro"]
|
|
71
|
+
print('SideFX search directory: "{}"'.format(houdini_dir))
|
|
72
|
+
docker_args.append(DOCKER_IMAGE)
|
|
73
|
+
subprocess.check_call(docker_args)
|
|
74
|
+
return 0
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cgcpp
|
|
3
|
+
Version: 1.8.2
|
|
4
|
+
Summary: CG C++ Support module
|
|
5
|
+
Author-email: Andriy Babak <ababak@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/ababak/cgcpp
|
|
8
|
+
Project-URL: Repository, https://github.com/ababak/cgcpp.git
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
[](https://github.com/ababak/cgcpp/actions/workflows/docker-image.yml)
|
|
12
|
+
|
|
13
|
+
# Computer Graphics C++ (cgcpp)
|
|
14
|
+
A universal C++ solution for common needs in computer graphics software.
|
|
15
|
+
|
|
16
|
+
### Supported Environments
|
|
17
|
+
- **Python & Boost Versions** (Windows):
|
|
18
|
+
- Python 3.9, Boost 1.76.0
|
|
19
|
+
- Python 3.10, Boost 1.80.0
|
|
20
|
+
- Python 3.11, Boost 1.82.0
|
|
21
|
+
- Python 3.12, Boost 1.85.0
|
|
22
|
+
- **Autodesk Maya** (Windows):
|
|
23
|
+
- Maya 2023: Python 3.9, Boost 1.76.0
|
|
24
|
+
- Maya 2024: Python 3.10, Boost 1.80.0
|
|
25
|
+
- Maya 2025: Python 3.11, Boost 1.82.0
|
|
26
|
+
- Maya 2026: Python 3.11, Boost 1.85.0
|
|
27
|
+
- **SideFX Houdini** (Windows):
|
|
28
|
+
- Houdini 19.5: Python 3.9, Boost 1.76.0
|
|
29
|
+
- Houdini 20.0: Python 3.10, Boost 1.80.0
|
|
30
|
+
- Houdini 20.5: Python 3.11, Boost 1.82.0
|
|
31
|
+
|
|
32
|
+
Support for additional platforms and DCC applications may be added in the future.
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
- **Isolated builds** inside a Docker container for a predictable environment
|
|
36
|
+
- **Python-C++ integration** to call C++ functions from Python
|
|
37
|
+
- **Dynamic library reloading** (updates libraries on each new call)
|
|
38
|
+
- **Python exception handling** from C++
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
Install in your Windows Python virtual environment:
|
|
42
|
+
|
|
43
|
+
python -m pip install git+https://github.com/ababak/cgcpp.git
|
|
44
|
+
|
|
45
|
+
or
|
|
46
|
+
|
|
47
|
+
pip install cgcpp
|
|
48
|
+
|
|
49
|
+
## Building Examples
|
|
50
|
+
|
|
51
|
+
mkdir out
|
|
52
|
+
python -m cgcpp examples/source_exception --out ./out
|
|
53
|
+
python -m cgcpp examples/source_maya --out ./out --maya
|
|
54
|
+
python -m cgcpp examples/source_houdini --out ./out --houdini
|
|
55
|
+
|
|
56
|
+
Ensure you have Maya and Houdini installed in their default locations as specified in `CMakeLists.txt`
|
|
57
|
+
|
|
58
|
+
## Testing Built Examples
|
|
59
|
+
Should throw `AttributeError: Some error` exception:
|
|
60
|
+
|
|
61
|
+
python -c 'import cgcpp;cgcpp.call(lib="out/lib_exception", func="call")'
|
|
62
|
+
|
|
63
|
+
Inside Maya:
|
|
64
|
+
|
|
65
|
+
import cgcpp
|
|
66
|
+
print(cgcpp.call(lib="out/maya_module", func="ls"))
|
|
67
|
+
|
|
68
|
+
Inside Houdini:
|
|
69
|
+
|
|
70
|
+
import cgcpp
|
|
71
|
+
print(cgcpp.call(lib="out/houdini_module", func="ls"))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
cgcpp/__init__.py,sha256=qf7rPszcBspZJtA33c7nQwnHju-ec-BzKX1mX-UXiF0,3881
|
|
2
|
+
cgcpp/__main__.py,sha256=SHNrpVIurEUdaCeHcorJn23jiP3O-6u41oY_qrcs6eg,2073
|
|
3
|
+
cgcpp/build.py,sha256=TizhFU3LBGCxUu0RnoTzSOMxAJIZpOzZGW1AButHXZg,2434
|
|
4
|
+
cgcpp/lib_loader_python310.pyd,sha256=RlKLAiIse_PtApdxfWuOPSIhHXF9mR0Om6n7CM8yyzI,134656
|
|
5
|
+
cgcpp/lib_loader_python311.pyd,sha256=hA8T1jXVZVqp85tpKl5-90U6c9a9Xqj61mD-iXJWsWs,134656
|
|
6
|
+
cgcpp/lib_loader_python312.pyd,sha256=LP6b_3yZjgvptXzGhB253kedmMuAySajjYEtgxjCam8,140288
|
|
7
|
+
cgcpp/lib_loader_python39.pyd,sha256=XJNC6gck1bGaD0MCcpMIGO4OCNorg3SnpSTgMnYpdlI,130048
|
|
8
|
+
cgcpp-1.8.2.dist-info/METADATA,sha256=nqgvIlu2tblbM6CL_DIbhVFqmQEH1HKrlLyUNvB1Cpc,2425
|
|
9
|
+
cgcpp-1.8.2.dist-info/WHEEL,sha256=Uot1xtv2NjZkWGfsbtixFxGSupJDmWFZZuntJdtO4yI,98
|
|
10
|
+
cgcpp-1.8.2.dist-info/top_level.txt,sha256=FiFBFxcRpL25SIiVvvzdLJgbYHR17k1haJMNvE2v3oM,6
|
|
11
|
+
cgcpp-1.8.2.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cgcpp
|