Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
setuptools_dso
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
setuptools_dso
Commits
9fbdc410
Commit
9fbdc410
authored
Mar 06, 2021
by
Michael Davidsaver
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add setuptools_dso.runtime
parent
8c9a6005
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
169 additions
and
24 deletions
+169
-24
.gitignore
.gitignore
+1
-1
example/setup.py
example/setup.py
+2
-0
example/src/dsodemo/cli.py
example/src/dsodemo/cli.py
+3
-2
example/src/dsodemo/ext/__init__.py
example/src/dsodemo/ext/__init__.py
+2
-2
src/setuptools_dso/__init__.py
src/setuptools_dso/__init__.py
+3
-0
src/setuptools_dso/dsocmd.py
src/setuptools_dso/dsocmd.py
+5
-19
src/setuptools_dso/runtime.py
src/setuptools_dso/runtime.py
+153
-0
No files found.
.gitignore
View file @
9fbdc410
...
...
@@ -9,4 +9,4 @@ build/
/env/
*.egg-info/
*_dso.py
*_dso
info
.py
example/setup.py
View file @
9fbdc410
...
...
@@ -28,6 +28,8 @@ setup(
# setup/build time dependencies listed in pyproject.toml
# cf. PEP 518
#setup_requires = ['setuptools_dso'],
# also need at runtime for DSO filename lookup since demo uses ctypes
install_requires
=
[
'setuptools_dso'
],
packages
=
[
'dsodemo'
,
'dsodemo.ext'
,
'dsodemo.lib'
],
package_dir
=
{
''
:
'src'
},
ext_modules
=
[
ext
],
...
...
example/src/dsodemo/cli.py
View file @
9fbdc410
...
...
@@ -3,14 +3,15 @@ from __future__ import print_function
import
ctypes
from
setuptools_dso
import
find_dso
from
.ext
import
dtest
from
.lib
import
demo_dsoinfo
def
main
():
print
(
dtest
.
foo
())
print
(
dtest
.
bar
())
# ctypes.RTLD_GLOBAL ensures we don't load a second instance.
demolib
=
ctypes
.
CDLL
(
demo_dsoinfo
.
sofilename
,
ctypes
.
RTLD_GLOBAL
)
demolib
=
ctypes
.
CDLL
(
find_dso
(
'dsodemo.lib.demo'
,
so
=
True
)
,
ctypes
.
RTLD_GLOBAL
)
myvar
=
ctypes
.
c_int
.
in_dll
(
demolib
,
'myvar'
)
dtest
.
check_myvar
(
ctypes
.
addressof
(
myvar
))
...
...
example/src/dsodemo/ext/__init__.py
View file @
9fbdc410
# import calls os.add_dll_directory() on windows
from
..lib
import
demo_dsoinfo
from
setuptools_dso
import
dylink_prepare_dso
dylink_prepare_dso
(
'..lib.demo'
)
src/setuptools_dso/__init__.py
View file @
9fbdc410
...
...
@@ -4,6 +4,7 @@ from __future__ import print_function
import
os
from
setuptools
import
setup
as
_setup
from
.dsocmd
import
DSO
,
Extension
,
build_dso
,
build_ext
,
bdist_egg
from
.runtime
import
dylink_prepare_dso
,
find_dso
from
setuptools.command.install
import
install
...
...
@@ -14,6 +15,8 @@ __all__ = (
'build_ext'
,
'bdist_egg'
,
'setup'
,
'dylink_prepare_dso'
,
'find_dso'
,
)
def
setup
(
**
kws
):
...
...
src/setuptools_dso/dsocmd.py
View file @
9fbdc410
...
...
@@ -413,34 +413,20 @@ class build_dso(dso2libmixin, Command):
textwrap.dedent(
"""
# generated by setuptools_dso
import
sys,
os
import os
# on windows, extend DLL search path to include
# the directory containing this file
def fixpath():
libdir = os.path.dirname(__file__)
if hasattr(os, '
add_dll_directory
'): # py >= 3.8
os.add_dll_directory(libdir)
elif sys.platform == "win32":
path = os.environ.get('
PATH
', '').split(os.pathsep)
path.append(libdir)
os.environ['
PATH
'] = os.pathsep.join(path)
fixpath()
del fixpath
dsoname = {dsoname!r}
dsoname = {dso.name!r}
libname = {libname!r}
soname = {soname!r}
depends = {dso.dsos!r}
dir = os.path.dirname(__file__)
filename = os.path.join(dir, libname)
sofilename = os.path.join(dir, soname)
del dir
del os
__all__ = ("dsoname", "libname", "soname", "filename", "sofilename")
"""
).format(dso
name=dso.name
,
).format(dso
=dso
,
libname=self._name2libname(dso),
soname=self._name2libname(dso, so=True))
)
...
...
src/setuptools_dso/runtime.py
0 → 100644
View file @
9fbdc410
"""
Tools for interacting with packages containing DSOs w/ dsoinfo modules
as built with setuptools_dso >= 2
"""
from
__future__
import
print_function
import
os
import
sys
import
logging
import
inspect
from
importlib
import
import_module
from
collections
import
OrderedDict
__all__
=
(
'dylink_prepare_dso'
,
'find_dso'
,
'import_dsoinfo'
,
)
_log
=
logging
.
getLogger
(
__name__
)
# shadow DSO runtime search path to avoid duplication.
# Only effective on windows.
_dso_dirs
=
set
()
def
add_dso_directory
(
path
):
path
=
os
.
path
.
normpath
(
path
)
# strictly speaking, only needed on windows.
# we enforce on all targets for consistency.
if
not
os
.
path
.
isabs
(
path
):
raise
ValueError
(
'DSO search pathes must be absolute: {0!r}'
.
format
(
path
))
elif
path
in
_dso_dirs
:
return
elif
hasattr
(
os
,
'add_dll_directory'
):
# py >= 3.8
os
.
add_dll_directory
(
path
)
elif
sys
.
platform
==
"win32"
:
paths
=
os
.
environ
.
get
(
'PATH'
,
''
).
split
(
os
.
pathsep
)
paths
.
append
(
path
)
os
.
environ
[
'PATH'
]
=
os
.
pathsep
.
join
(
paths
)
_log
.
debug
(
'Extend DSO search path to {0!r}'
.
format
(
path
))
_dso_dirs
.
add
(
path
)
def
_dso2info
(
dso
):
"""Return mangled name of DSO info module.
eg. 'my.pkg.libs.adso' -> 'my.pkg.libs.adso_dsoinfo'
"""
parts
=
dso
.
split
(
'.'
)
parts
[
-
1
]
=
'{}_dsoinfo'
.
format
(
parts
[
-
1
])
return
'.'
.
join
(
parts
)
def
_auto_pkg
():
# look 2 frames down in the call stack
caller_frame
=
inspect
.
stack
()[
2
][
0
]
caller_mod
=
inspect
.
getmodule
(
caller_frame
)
return
caller_mod
.
__name__
def
import_dsoinfo
(
dso
,
package
=
None
):
"""Import and return info module for the named DSO
:param str dso: DSO name string (eg. 'my.pkg.libs.adso').
:param str package: Package name to resolve relative imports. cf. importlib.import_module
:returns: Info module
"""
if
package
is
None
:
package
=
_auto_pkg
()
return
import_module
(
_dso2info
(
dso
),
package
=
package
)
def
dylink_prepare_dso
(
dso
,
package
=
None
):
"""Take steps necessary to allow the named DSO to be loaded implicitly.
eg. On Windows, call `os.add_dll_directory()` as neeeded.
:param str dso: DSO name string (eg. 'my.pkg.libs.adso').
:param str package: Package name to resolve relative imports. cf. importlib.import_module
:returns: Info module for the named DSO
"""
if
package
is
None
:
package
=
_auto_pkg
()
todo
,
found
=
[
dso
],
OrderedDict
()
# recursively walk dependencies
while
todo
:
working
=
todo
.
pop
(
0
)
info
=
import_dsoinfo
(
working
,
package
=
package
)
found
[
working
]
=
info
# libdir must be absolute, but __file__ may be relative if imported via $PWD
libdir
=
os
.
path
.
join
(
os
.
getcwd
(),
os
.
path
.
dirname
(
info
.
__file__
))
add_dso_directory
(
libdir
)
todo
.
extend
([
t
for
t
in
info
.
depends
if
t
not
in
found
])
return
next
(
iter
(
found
.
values
()))
# first value
def
find_dso
(
dso
,
package
=
None
,
so
=
True
):
"""Lookup DSO file name. eg. for use with ctypes
:param str dso: DSO name string (eg. 'my.pkg.libs.adso').
:param str package: Package name to resolve relative imports. cf. importlib.import_module
:param bool so: When True (default) return SO qualified name.
eg. "libblah.so.0" vs. "libblah.so".
No effect on Windows.
:returns: Absolute path string of DSO file.
eg.
>>> fname = setuptools_dso.find_dso('my.pkg.libs.adso')
>>> lib = ctypes.CDLL(fname, , ctypes.RTLD_GLOBAL)
"""
if
package
is
None
:
package
=
_auto_pkg
()
mod
=
dylink_prepare_dso
(
dso
,
package
=
package
)
return
mod
.
sofilename
if
so
else
mod
.
filename
def
cli_info
(
args
):
mod
=
import_dsoinfo
(
args
.
dso
)
if
args
.
var
:
print
(
getattr
(
mod
,
args
.
var
))
else
:
for
var
in
dir
(
mod
):
if
not
var
.
startswith
(
'_'
):
print
(
'{} = {!r}'
.
format
(
var
,
getattr
(
mod
,
var
)))
def
getargs
():
from
argparse
import
ArgumentParser
P
=
ArgumentParser
()
P
.
add_argument
(
'-v'
,
'--debug'
,
dest
=
'level'
,
default
=
logging
.
INFO
,
action
=
'store_const'
,
const
=
logging
.
DEBUG
)
SP
=
P
.
add_subparsers
()
S
=
SP
.
add_parser
(
'info'
)
S
.
add_argument
(
'dso'
)
S
.
add_argument
(
'var'
,
nargs
=
'?'
)
S
.
set_defaults
(
func
=
cli_info
)
return
P
def
main
():
args
=
getargs
().
parse_args
()
logging
.
basicConfig
(
level
=
args
.
level
)
logging
.
debug
(
'PYTHONPATH='
)
for
ent
in
sys
.
path
:
logging
.
debug
(
' '
+
ent
)
args
.
func
(
args
)
if
__name__
==
'__main__'
:
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment