A Python script that creates a new EPICS motor driver module by cloning the motorExample template and replacing all references to "example" / "Example" / "EXAMPLE" with user-specified names.
- Python 3.6+
- Git
python createMotorDriverModule.py <ModuleName> [--driver <DriverName>] [--class <ClassName>] [--url <git_url>]
| Argument | Required | Description |
|---|---|---|
ModuleName |
Yes | Module name (e.g., Vendor, AcsMotion, VMC). The output directory will be motor<ModuleName>. |
--driver DriverName |
No | Driver name used for source filenames (.cpp, .h, .dbd). When --class is not specified, also controls C++ class names and iocsh functions. Defaults to ModuleName. |
--class ClassName |
No | C++ class name prefix, used as-is for Controller/Axis classes, iocsh registration functions, and #define constants. When specified, --driver controls only source filenames while the module name controls directories, library name, and build artifacts. Defaults to --driver value. |
--url URL |
No | Git clone URL for the motorExample template. Defaults to https://github.com/epics-motor/motorExample.git. A local path can also be used. |
# Simple case -- module and driver use the same name:
python createMotorDriverModule.py Vendor
# Two-name case -- module name differs from driver/class name:
python createMotorDriverModule.py AcsMotion --driver SPiiPlus
# Three-name case -- module, driver, and class names all differ:
python createMotorDriverModule.py VMC --driver vmc --class VirtualMotor
# Clone from a local path instead of GitHub:
python createMotorDriverModule.py Vendor --url /path/to/motorExampleThe module name uses CamelCase-aware lowering (only the first character is
lowered) for the lowercase form. All-uppercase names use simple .lower():
| Input | lowercase | title-case | uppercase |
|---|---|---|---|
Vendor |
vendor |
Vendor |
VENDOR |
AcsMotion |
acsMotion |
AcsMotion |
ACSMOTION |
VMC |
vmc |
VMC |
VMC |
The driver name uses simple .lower() for the lowercase form:
| Input | lowercase | title-case | uppercase |
|---|---|---|---|
SPiiPlus |
spiiplus |
SPiiPlus |
SPIIPLUS |
The driver name is used as-is for source filenames only. The class name is
used as-is for C++ identifiers, with .upper() for #define constants.
All other naming (directories, library, dbd build artifacts, IOC binary) uses
the module name:
| Name | As-is | .upper() |
|---|---|---|
--driver vmc |
vmc |
-- |
--class VirtualMotor |
VirtualMotor |
VIRTUALMOTOR |
The replacement strategy depends on whether --class is specified.
These handle directory names, Makefile targets, RELEASE macros, iocsh paths, LICENSE text, and all general references:
| Template pattern | Replacement |
|---|---|
motorExample |
motor<TitleCase> |
MOTOREXAMPLE |
MOTOR<UPPERCASE> |
MOTOR_EXAMPLE |
MOTOR_<UPPERCASE> |
Example |
<TitleCase> |
example |
<lowercase> |
EXAMPLE |
<UPPERCASE> |
When --driver is specified, these are applied before the module-scoped
replacements in driver-related files. They replace the ExampleMotor compound
as a unit, effectively removing "Motor" from class names:
| Template pattern | Replacement | Example |
|---|---|---|
ExampleMotor |
<DriverTitle> |
ExampleMotorController -> SPiiPlusController |
EXAMPLE_MOTOR |
<DRIVER_UPPER> |
NUM_EXAMPLE_MOTOR_PARAMS -> NUM_SPIIPLUS_PARAMS |
ExampleDriver |
<DriverTitle>Driver |
ExampleDriver.cpp -> SPiiPlusDriver.cpp |
example motor |
<driverLower> |
"example motor controller" -> "spiiplus controller" |
When --class is specified, replacements are split across three levels:
Handles compound patterns and general Example/example in non-support files
(IOC Makefiles, iocBoot scripts, RELEASE files, directories, etc.):
| Template pattern | Replacement | Controls |
|---|---|---|
motorExample |
motor<Module> |
Module directory, iocsh paths |
MOTOR_EXAMPLE |
MOTOR_<MODULE> |
RELEASE macros |
MOTOREXAMPLE |
MOTOR<MODULE> |
LICENSE |
EXAMPLE |
<MODULE> |
INSTANCE macros |
Example |
<ModuleTitle> |
Library name, support dbd, Makefile prefixes, IOC refs |
example |
<moduleLower> |
Directories, IOC binary, filenames |
Only the source filenames (.cpp, .h) and source .dbd file use the driver
name. The library name and build dbd use the module name:
| Template pattern | Replacement | Controls |
|---|---|---|
ExampleDriver |
<driver>Driver |
Source filenames (vmcDriver.cpp), #include |
Example.dbd |
<driver>.dbd |
Source dbd file (vmc.dbd) |
| Template pattern | Replacement | Controls |
|---|---|---|
ExampleMotor |
<ClassName> |
C++ classes, iocsh functions, registrar |
EXAMPLE_MOTOR |
<CLASSNAME> |
#define constants |
example motor |
<classname> |
Error message strings |
Files starting with EXAMPLE_ (an EPICS convention for example configuration
files) retain their EXAMPLE_ prefix in both filenames and content references:
EXAMPLE_CONFIG_SITE.local-- unchangedEXAMPLE_RELEASE.local-- unchangedEXAMPLE_motorExample.substitutions->EXAMPLE_motorVendor.substitutions
For python createMotorDriverModule.py Vendor:
motorVendor/
├── configure/
│ ├── EXAMPLE_CONFIG_SITE.local
│ ├── EXAMPLE_RELEASE.local
│ ├── RELEASE
│ └── ...
├── vendorApp/
│ ├── Db/
│ ├── iocsh/
│ │ ├── EXAMPLE_motorVendor.substitutions
│ │ └── motorVendor.iocsh
│ └── src/
│ ├── VendorDriver.cpp
│ ├── VendorDriver.h
│ ├── Vendor.dbd
│ └── Makefile
├── iocs/
│ └── vendorIOC/
│ ├── configure/
│ ├── vendorApp/src/
│ └── iocBoot/iocVendor/
│ ├── st.cmd
│ └── ...
├── LICENSE
└── Makefile
For python createMotorDriverModule.py VMC --driver vmc --class VirtualMotor:
motorVMC/
├── configure/
│ └── ...
├── vmcApp/ # directory uses module name
│ ├── iocsh/
│ │ ├── EXAMPLE_motorVMC.substitutions
│ │ └── motorVMC.iocsh
│ └── src/
│ ├── vmcDriver.cpp # source filename uses driver name
│ ├── vmcDriver.h # VirtualMotorController/Axis inside
│ ├── vmc.dbd # source dbd uses driver name
│ └── Makefile # LIBRARY_IOC += VMC (module name)
├── iocs/
│ └── vmcIOC/ # IOC directory uses module name
│ ├── vmcApp/src/
│ │ └── Makefile # PROD_IOC = vmc, vmc_LIBS += VMC
│ └── iocBoot/iocVMC/
│ ├── st.cmd
│ └── ...
├── LICENSE
└── Makefile
- Clones the motorExample template into a temporary directory
- Removes the template's
.git/history - Applies content replacements (class-scoped first, then module/driver-scoped)
- Renames files (driver source files use the driver name, all others use the module name)
- Renames directories (always uses the module name)
- Moves the result to the current working directory as
motor<ModuleName> - Initializes a fresh git repository