Thank you for contributing to ModbusTools. This guide explains how to set up the project, make changes, and submit them for review.
- Main repository builds two GUI apps:
mbclientandmbserver - Shared core library:
mbcoreinsrc/core - Protocol library is a Git submodule:
modbus(ModbusLib) - Primary build system: CMake
- Legacy build/test files with qmake still exist
- Git
- CMake >= 3.13
- C++ compiler
- Windows: MSVC
- Linux: GCC or Clang
- Qt 5.8+ (Qt 5.15.x recommended)
- Python 3.6+
- PyQt5
git clone https://github.com/serhmarch/ModbusTools.git
cd ModbusTools
git submodule update --init --recursiveThe modbus directory is a submodule. Always initialize/update it before building.
Top-level CMake presets are defined in CMakePresets.json.
cmake --preset Win64-MSVC
cmake --build --preset Win64-MSVC-Debug
cmake --build --preset Win64-MSVC-ReleaseOptional targets:
cmake --build --preset Win64-MSVC-Debug --target mbclient
cmake --build --preset Win64-MSVC-Debug --target mbserverQuick script from repo root:
./build.batcmake --preset Linux-Debug
cmake --build --preset Linux-Debug
cmake --preset Linux-Release
cmake --build --preset Linux-ReleaseQuick script from repo root:
./build.shTop-level options (see root CMakeLists.txt):
MBTOOLS_CLIENT_ENABLED=ON|OFFMBTOOLS_SERVER_ENABLED=ON|OFFMBTOOLS_PACKAGE=ON|OFF
Example:
cmake --preset Win64-MSVC-Client
cmake --build --preset Win64-MSVC-Client-ReleaseUnit tests are maintained in the modbus submodule and are enabled by MB_TESTS_ENABLED.
cmake -S modbus -B build/modbus-tests -DMB_TESTS_ENABLED=ON -DMB_EXAMPLES_ENABLED=OFF
cmake --build build/modbus-tests
ctest --test-dir build/modbus-tests --output-on-failureNotes:
- If Qt-specific tests are needed, configure ModbusLib with
-DMB_QT_ENABLED=ON - On Windows, ensure Qt runtime DLLs are discoverable when running tests
There is also a legacy qmake test layout under tests/ (for example tests/test_core/test_core.pro).
Use this only if your change targets that workflow.
Documentation is generated via doc/CMakeLists.txt when Doxygen is found.
- Doxygen is auto-detected
- Graphviz
dotis optional (enables diagrams) - Qt help generator is optional (produces qch/qhc)
Build docs by running a regular CMake build. Relevant targets are created automatically when tools are found.
src/core- shared application core (mbcore)src/client- client application (mbclient)src/server- server application (mbserver)modbus/src- protocol library implementation (submodule)doc- doxygen config/templates and help project filespackage- CPack and installer integration
No strict formatter config is committed (no repo-wide .clang-format/.editorconfig), so consistency with nearby code is required.
The patterns below are based on current files in src/core, src/client, src/server, and modbus/src.
- Application/core classes use
mbprefix and PascalCase, for examplembCoreProject,mbServerProject. - Use
mbCore...prefixmbcore-lib classes. - Use
mbClient...prefix formbclient-app classes. - Use
mbServer...prefix formbserver-app classes. - Modbus library classes use
Modbus...naming, for exampleModbusClientPort. - Member fields use
m_prefix, for examplem_project,m_ctrlRun. - Qt signal/slot helper methods commonly use
slot...names. - Public API in headers is often grouped with labeled sections such as
public: // settings,public: // devices.
- Prefer Qt macros/idioms already used in the project:
Q_OBJECT,Q_SIGNALS,Q_EMITQStringLiteral(...)for compile-time string literals- existing containers/types such as
QList,QHash,QVariant
- Existing code still uses
Q_FOREACHin many places. Do not mass-convert loops in unrelated files.
- Use 4 spaces indentation, no tabs.
- Keep opening brace on the new line for functions, conditionals, and loops:
void func1(int a, int b)
{
if (a < b)
{
doSomething();
for (int i = 0; i < MAX; i++)
{
// for loop
}
}
else
{
doSomethingElse();
while (condition)
{
// while loop
}
}
}- Use readable multiline conditions, for example:
if ((index >= 0) && (index < m_ports.count()))
m_ports.insert(index, port);- Keep early returns for guard clauses.
- Use pointer/reference symbol at variable name, like
Type *vorType &v, because in C/C++ pointer/reference is related to a variable, not a type.
- New source/header files should include the project license header block used in existing files.
- Keep include order stable and minimal:
- own header first in
.cpp - then Qt/standard/project headers in the file's existing style
- own header first in
- Do not reorder includes broadly unless required for correctness.
- Avoid broad refactoring in feature/bugfix PRs.
- Keep behavior-compatible changes unless the PR explicitly targets a breaking change.
- For shared abstractions (
src/coreandmodbus/src), check impact on both client and server paths.
- Prefer comments that explain intent and constraints, not obvious mechanics.
- Use Doxygen-style comments for public library APIs where surrounding code already uses Doxygen style (especially in
modbus/src).
- When in doubt, copy the style from the nearest existing file in the same module.
- Keep diffs focused: functional change first, formatting-only changes only when necessary.
- Make small, logical commits
- Use imperative commit titles
- Reference issues when applicable
Examples:
Fix scanner unit range validationAdd timeout guard for TCP read loopUpdate server scripting docs for Python 3.6+
When opening a PR, include:
- What changed
- Why it changed
- How it was tested
- Platform(s) tested (Windows/Linux)
- Any compatibility or migration notes
Before requesting review:
- Build succeeds for the affected target(s)
- Relevant tests pass
- Documentation is updated when behavior/UI changes
- Submodule changes are intentional and clearly described
If your PR updates code in modbus:
- Commit changes in the ModbusLib repository first (or use your fork)
- Update this repository to the new submodule commit
- In the PR description, explain exactly why the submodule pointer changed
Avoid accidental submodule pointer updates.
- Packaging is controlled by
MBTOOLS_PACKAGE - Install layout variables are in
cmake/InstallDirs.cmake - On Windows, CMake install logic includes Qt runtime DLLs/plugins
If your change affects runtime dependencies, verify cmake --install output before merging.
Use GitHub issues with:
- Reproduction steps
- Expected behavior vs actual behavior
- OS, compiler, Qt version
- Logs/screenshots when useful
Also check project planning notes in TODO to avoid duplicates.
By contributing, you agree your contributions are licensed under GPL-3.0 (see LICENSE).