Build a managed library
This guide is a worked, end-to-end tutorial for building a managed library:
a Teamcenter server-side shared library whose registration machinery tcli
generates and keeps wired up for you. We start from an empty, initialized
project and grow one library, libsample, through every extension kind, a
runtime property, an action handler, a rule handler, an operation extension, and
a common module. Then add an Active Workspace kit alongside it.
For the exhaustive flag list, see the add reference.
Prerequisites
Section titled “Prerequisites”- An initialized project (
tcli init --tc-version <release>), so a.tcli.yamlmanifest exists in the working directory. See the quick start. - tcli on your
PATH. Every command below is run from the project root.
What a managed library is
Section titled “What a managed library is”A simple library (--simple) is just a CMake target you fill in yourself. A managed library additionally ships the registration plumbing Teamcenter
customisations need, and marks itself manageable: true in the manifest so tcli
can grow it later with add extension.
Concretely, a managed library ships:
- A single registration entry point.
register.cppexposes<lib>_register_callbacks(), which registers aUSER_gs_shell_init_moduleexit that in turn calls<lib>_register_customisations(). Every extension you add is registered from there. - Reusable registration helpers (
register_tools.cpp/.hpp). Thin, exception-safe wrappers such asreg::ActionHandler,reg::RuleHandler, andreg::RuntimePropString/Int/Double/Date/Tag(and their...sarray overloads). A failed registration is logged to the Teamcenter syslog instead of crashing the server; the library still loads. - A CMake build wired for Teamcenter (
tc_target_configure_library,tc_target_link_library, export macros inexports.hpp, per-kind source lists). - Empty, ready-to-grow subdirectories for each extension kind.
1. Create the library
Section titled “1. Create the library”tcli add library --name libsample --iplib none--namemust start with the lowercase prefixlib(e.g.libsample).--iplibselects thetc_configure_libraryregistration mode (none,libuser_exits, orlibserver_exits); it defaults tononeand is ignored for non-manageable libraries.
This appends libsample to the manifest and writes the tree under
customisation/tc/server/.
What it generated
Section titled “What it generated”The library itself lives under customisation/tc/server/libsample/:
customisation/tc/server/libsample/├── CMakeLists.txt # builds the libsample shared target├── README.md└── libsample/ ├── constants.hpp # kLibraryName, custom error codes ├── exports.hpp # LIBSAMPLE_API import/export macro ├── register.hpp ├── register.cpp # the single registration entry point ├── register_tools.hpp ├── register_tools.cpp # reg:: registration helpers ├── syslog.hpp # syslog helper functions ├── action_handlers/ # CMakeLists.txt + action_handlers.hpp ├── rule_handlers/ # CMakeLists.txt + rule_handlers.hpp ├── runtime_props/ # CMakeLists.txt + runtime_props.hpp ├── op_extensions/ # CMakeLists.txt + op_extensions.hpp └── modules/ # CMakeLists.txtThe first library or tool scaffolded into a project also creates the shared
build scaffolding at the customisation/tc/server/ root, and registers the new
library in it:
customisation/tc/server/├── CMakeLists.txt # customisation root; add_subdirectory(libsample)├── CMakePresets.json # Debug and release presets for ninja using MSVC├── .clang-format # Formatting configuration├── .clangd # Clangd LSP configuration└── cmake/ # shipped Tc.cmake helper modules2. How registration works
Section titled “2. How registration works”Understanding the wiring makes the rest of the guide obvious. Files contain
marker regions, matched // tcli:begin:<id> / // tcli:end:<id> pairs,
that tcli patches when you add an extension:
register.cpphas one region per registerable kind, e.g.register:action_handler,register:rule_handler,register:runtime_prop.- The shared header in each subdirectory (
action_handlers.hpp,rule_handlers.hpp,runtime_props.hpp,op_extensions.hpp) has adeclarationsregion, and each subdirectoryCMakeLists.txthas asourcesregion.
When you run add extension, tcli renders the new source file, inserts its
declaration into the shared header, adds it to the CMake source list, and (for
kinds that self-register) inserts the reg:: call into register.cpp. Every
change is applied in a single transactional plan. It either all lands or
nothing does, and it refuses to overwrite files that already exist.
You never edit the marker regions by hand; you edit the generated implementation files, which is where each section below points you.
3. Add a runtime property
Section titled “3. Add a runtime property”A runtime property computes a business object property value on the fly.
tcli add extension rtp --library libsample --name my4_custom_prop \ --type-name ItemRevision --prop-name my4CustomProp \ --value-type stringFor a multi-valued property, add --array (this selects the ...s registration
overload, e.g. RuntimePropStrings). Supported --value-type values are
string, int, double, date, and tag.
Files created / patched (under customisation/tc/server/libsample/libsample/):
-
+ runtime_props/my4_custom_prop.cpp— the implementation. -
~ runtime_props/runtime_props.hpp— declaration inserted. -
~ runtime_props/CMakeLists.txt— source added. -
~ register.cpp— registration inserted into theregister:runtime_propregion:libsample::reg::RuntimePropString("ItemRevision", "my4CustomProp", my4_custom_prop);
Where to implement: open runtime_props/my4_custom_prop.cpp and replace the
// Implementation goes here body of my4_custom_prop_impl(METHOD_message_t* msg, va_list args).
4. Add an action handler
Section titled “4. Add an action handler”An EPM action handler runs custom logic at a workflow action.
tcli add extension ah --library libsample \ --name my_release_targets \ --handler-name MY-release-targets--nameis the C++ function/file identifier (snake_case).--handler-nameis the EPM handler name registered with Teamcenter and referenced by workflows, an uppercase-prefixed, hyphenated name such asMY-release-targets.
Files created / patched:
-
+ action_handlers/my_release_targets.cpp— the implementation. -
~ action_handlers/action_handlers.hpp— declaration inserted. -
~ action_handlers/CMakeLists.txt— source added. -
~ register.cpp— registration inserted into theregister:action_handlerregion:libsample::reg::ActionHandler("MY-release-targets", "MY-release-targets", emx_release_targets); -
+ configuration/aw_workflow_handlers/MY-release-targets.json— the Active Workspace workflow-handler definition, so the handler is selectable in the AW workflow designer. Deploy it withtcli deploy aw_workflow_handlers.
Where to implement: edit the // Implementation goes here body of
my_release_targets_impl(EPM_action_message_t msg).
5. Add a rule handler
Section titled “5. Add a rule handler”An EPM rule handler returns a decision that gates a workflow transition. It is
the same shape as an action handler, differing only in the registered helper and
the EPM_decision_t return type.
tcli add extension rh --library libsample \ --name my_check_maturity \ --handler-name MY-check-maturityFiles created / patched:
-
+ rule_handlers/my_check_maturity.cpp— the implementation. -
~ rule_handlers/rule_handlers.hpp— declaration inserted. -
~ rule_handlers/CMakeLists.txt— source added. -
~ register.cpp— registration inserted into theregister:rule_handlerregion:libsample::reg::RuleHandler("MY-check-maturity", "MY-check-maturity", emx_check_maturity); -
+ configuration/aw_workflow_handlers/MY-check-maturity.json— the AW workflow-handler definition.
Where to implement: edit my_check_maturity_impl(EPM_rule_message_t msg) and
return an EPM_decision_t (e.g. EPM_go / EPM_nogo).
6. Add an operation extension
Section titled “6. Add an operation extension”An operation extension customises a business object or property operation via a pre-condition, pre-action or post-action.
tcli add extension boext --library libsample --name my_bo_extenstion \ --type-name ItemRevision --method-name fnd0Save \ --ext-type post-action --framework metaFiles created / patched:
+ op_extensions/my_bo_extension.cpp— the implementation.~ op_extensions/op_extensions.hpp— declaration inserted.~ op_extensions/CMakeLists.txt— source added.
There is no register.cpp change: BMIDE wires the operation to your function.
Where to implement: edit the body of my_bo_extension_impl().
7. Add a common module
Section titled “7. Add a common module”A common module is a self-contained helper (shared utilities, a small class) that other extensions in the library can include. It is not registered with Teamcenter and has no shared header to patch.
tcli add extension module --library libsample \ --name string_utilsFiles created / patched:
+ modules/string_utils.hpp— the module header (fill in your declarations).+ modules/string_utils.cpp— the module implementation.~ modules/CMakeLists.txt— source added.
Where to implement: put your declarations in string_utils.hpp and their
definitions in string_utils.cpp, both inside the libsample namespace. Include
it from other extensions with #include "../modules/string_utils.hpp".
8. Add an Active Workspace kit
Section titled “8. Add an Active Workspace kit”Server extensions are only half of most customisations. An AW kit holds the client-side Active Workspace contributions and lives in a separate root.
tcli add awkit --name customModule --aw-version 7.0.0--namemust be camelCase (e.g.customModule).--aw-versionis required and must match your Active Workspace release.
This creates the AW customisation root and the module sources:
customisation/tc/aw/├── awbuild.cmd # AW build script for your release└── stage/src/customModule/ ├── kit.json └── module.json9. Build
Section titled “9. Build”The shared CMake presets are generated at customisation/tc/server/. Configure
and build the server customisations from there with your Teamcenter-configured
toolchain, for example:
cd customisation/tc/servercmake --preset debugcmake --build --preset debugcmake --install build/debugBuild the AW kit with the generated customisation/tc/aw/awbuild.cmd.
Finally register the library in the TC_customization_libraries site preference.
addreference — every flag.- Extension kinds — the kinds at a glance.
deploy & export— deploying config artifacts such as the generatedaw_workflow_handlers.