You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a source file that has a dependency and I want to force cppimport to recompile the source when the dependency version changes. Unfortunately the header files of the dependency can remain the same when the version changes so I can't rely on that.
I have a Python function that obtains the version of the dependency, what's the best way to force cppimport too recompile given this information? Would it be possible to add functionality so you can pass a string to be included in the checksum calculation (cppimport.checksum._calc_cur_checksum)?
The snippet that I wrote above would work with no changes. In practice, I'd probably write out the version file as part of the process that updates dependencies. Or, do something like pip freeze > deps (substitute in the equivalent list of package versions for your setup). Then, the cfg['dependencies'].append(version_or_deps_filename) would be either in the preamble of the .cpp file or in the code that imports the file.
Then, elsewhere, whenever you want to update the dependency versions, you write to that file. How exactly you write to it will depend on your exact application, but one application might be something like:
Currently, if the dependencies haven't changed and the extension seems built and importable then the expected behavior is to import the extension without re-running the template.
I'd be open to changing the behavior so that we always run the templates on import. Or at least providing an option to run the template. One thing I'd be curious about is the performance impact of running the template during every import. Are we adding 500us or 50ms to the import time in the average case?
Another related issue here is that the cppimport configuration is currently unpleasantly global. If we're adding another configuration option, it might be time to either make the configuration something that can be passed to the imp(...) function or add a built-in configuration context manager so that configuration variables can easily be set just for the duration of a single import.
import os
from cppimport.importer import is_build_needed, setup_module_data
from cppimport.templating import run_templating
cpp_code = """// cppimport
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(source, m) {
m.def("add", &add);
}
/*
<%
import random
with open('versionsX', 'w') as f:
f.write(str(0))
cfg['dependencies'].append('versionsX')
setup_pybind11(cfg)
%>
*/
"""
with open('source.cpp', 'w') as f:
f.write(cpp_code)
filepath = os.path.abspath('source.cpp')
fullname = os.path.splitext(os.path.basename(filepath))[0]
module_data = setup_module_data(fullname, filepath)
is_build_needed(module_data)
# run_templating(module_data) # << uncomment for comparison
# No templating
$ python3 -m timeit -n 1000 "exec(open('scratch.py').read())"
1000 loops, best of 5: 494 usec per loop
# With templating
$ python3 -m timeit -n 1000 "exec(open('scratch.py').read())"
1000 loops, best of 5: 2.04 msec per loop
So its around 10 times slower.
I think for our purpose it should be ok to write to the dependency file before importing the module. I will explore that option.
Activity
tbenthompson commentedon Aug 1, 2022
Would it be feasible to do something like this:
The
'dependencies'configuration variable doesn't actually do anything with the contents so the paths provided can be any sort of file you want.joshlk commentedon Aug 1, 2022
Yer that could work. That's not easily doable at the moment right?
tbenthompson commentedon Aug 1, 2022
The snippet that I wrote above would work with no changes. In practice, I'd probably write out the
versionfile as part of the process that updates dependencies. Or, do something likepip freeze > deps(substitute in the equivalent list of package versions for your setup). Then, thecfg['dependencies'].append(version_or_deps_filename)would be either in the preamble of the.cppfile or in the code that imports the file.Does that make sense? Am I missing a piece?
joshlk commentedon Aug 2, 2022
Ow do you mean to add this to the template comment in the source file?
But would that trigger a rebuild as the template is only read if it's determined that a rebuild is needed?
tbenthompson commentedon Aug 2, 2022
Here's a more explicit version of what I'm imagining. Two files:
This will result in a rebuild any time the
dependency_versions.lockfile is updated. The list of dependencies is stored in an appendix to the shared library.Then, elsewhere, whenever you want to update the dependency versions, you write to that file. How exactly you write to it will depend on your exact application, but one application might be something like:
Is this useful?
joshlk commentedon Aug 4, 2022
Thanks - the above works but it would be better if the dependency file was generated on the fly. This code doesn't seem to work:
Here the dependency file is generated in the template. From looking at the cppimport code I don't understand why the template isn't run a second time.
tbenthompson commentedon Aug 5, 2022
Yes, it's as intended that the template is not being run a second time here. You can see the check for whether to enter the build step here:
cppimport/cppimport/__init__.py
Line 86 in e19e9a6
Currently, if the dependencies haven't changed and the extension seems built and importable then the expected behavior is to import the extension without re-running the template.
I'd be open to changing the behavior so that we always run the templates on import. Or at least providing an option to run the template. One thing I'd be curious about is the performance impact of running the template during every import. Are we adding 500us or 50ms to the import time in the average case?
Another related issue here is that the cppimport configuration is currently unpleasantly global. If we're adding another configuration option, it might be time to either make the configuration something that can be passed to the
imp(...)function or add a built-in configuration context manager so that configuration variables can easily be set just for the duration of a single import.joshlk commentedon Aug 9, 2022
Ok I tested it here:
scratch.py:So its around 10 times slower.
I think for our purpose it should be ok to write to the dependency file before importing the module. I will explore that option.
Thanks for all the help!