Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ability to link to additional libraries for from_file processors #1366

Merged
merged 2 commits into from
Jun 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 35 additions & 8 deletions Framework/python/ldmxcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, instanceName, className, moduleName):


@classmethod
def from_file(cls, source_file, class_name = None, instance_name = None, compile_notice = True, **config_kwargs):
def from_file(cls, source_file, class_name = None, needs = [], instance_name = None, compile_notice = True, **config_kwargs):
"""Construct an event processor "in place" from the passed source file

Since Framework dynamically loads libraries containing processors after
Expand All @@ -60,11 +60,12 @@ def from_file(cls, source_file, class_name = None, instance_name = None, compile

Note
----
We only link the compiled library with the Framework library. This means the single-file
processor only can access Framework and the event objects. If you desire your processor
to access other code from other modules within ldmx-sw, you should put your processor
within a module in ldmx-sw rather than running it stand-alone.

Developing processors in this way is incredible inefficient, especially since it
does not allow for code to be well organized and split across many files nor does it
allow for two processors to share common code.
If you find yourself defining more than one `class` within your new C++ processor,
it is highly recommended to transition your workflow to including your processor as a
part of ldmx-sw so that it can fully benefit from a build system.

Parameters
----------
Expand All @@ -73,13 +74,36 @@ def from_file(cls, source_file, class_name = None, instance_name = None, compile
class_name: str, default is name of source file
name of C++ class that is the processor
defaults to the name of the source file without an extension
needs: list[str]
Names of libraries that should be linked to the compiled processor in addition to 'Framework'
which is linked be default.
For example, one can gain access to the detector ID infrastructure with 'DetDescr'.
instance_name: str, default is class_name
name to give to instance of this C++ processor
compile_notice: bool, default is True
print a notice when compilation is triggered
config_kwargs: dict[str, Any]
configuration parameters to give to the processor

Examples
--------
A basic walkthrough is available online. https://ldmx-software.github.io/analysis/ldmx-sw.html

If `MyAnalyzer.cxx` contains the class `MyAnalyzer`, then we can put

p.sequence = [ ldmxcfg.Analyzer.from_file('MyAnalyzer.cxx') ]

In our config script to run the analyzer on its own in the sequence.
This default configuration only links the Framework library and so the analyzer
would only be able to access the Framework and event objects.
If you needed another library (for example, the 'DetDescr' library has the ID classes),
one can also

p.sequence = [ ldmxcfg.Analyzer.from_file('MyAnalyzer.cxx', needs = ['DetDescr']) ]

To inform the compiler that it should link your analyzer with the 'DetDescr' library.
**No removal of the library is done** so if you change the `needs` or some other parameter
to `from_file` you should also remove the library file (`*.so`) before attempting to re-run.

Returns
-------
Expand Down Expand Up @@ -110,14 +134,17 @@ def from_file(cls, source_file, class_name = None, instance_name = None, compile
' (or library does not exist), recompiling...'
)
import subprocess
libs_to_link = set(['Framework']+needs)
subprocess.run([
'g++', '-fPIC', '-shared', # construct a shared library for dynamic loading
'-o', str(lib), str(src), # define output file and input source file
'-lFramework', # link to Framework library (and the event dictionary)
]+[
f'-l{lib}' for lib in libs_to_link
]+[
'-I/usr/local/include/root', # include ROOT's non-system headers
'-I@CMAKE_INSTALL_PREFIX@/include', # include ldmx-sw headers (if non-system)
'-L@CMAKE_INSTALL_PREFIX@/lib', # include ldmx-sw libs (if non-system)
], check=True)
], check=True)
if compile_notice:
print(f'done compiling {src}')

Expand Down
Loading