diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..ec068fb8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,165 @@ +# PIP Codebase Guide for AGENTS + +## Build Commands + +### Basic Build +```bash +# Configure with CMake (release build) +cmake -B build + +# Build the project +cmake --build build + +# Install (default system location) +cmake --build build --target install + +# Local install (bin/lib/include in build directory) +cmake -B build -DLOCAL=ON +``` + +### With Tests +```bash +cmake -B build -DTESTS=ON +cmake --build build +cd build && ctest +``` + +### Build Only +```bash +cmake --build build +``` + +### Run Single Test +```bash +# After building with TESTS=ON +./build/tests/math/pip_math_test --gtest_filter="Vector2DTest.defaultConstructor*" +# Or use ctest +ctest -R math -V +# List all tests +ctest -N +``` + +### Build Options +- `TESTS=ON` - Build tests (requires Google Test) +- `COVERAGE=ON` - Build with coverage instrumentation +- `ICU=ON` - Enable ICU support for string conversion +- `STD_IOSTREAM=ON` - Enable std::iostream operators +- `INTROSPECTION=ON` - Build with introspection support +- `PIP_BUILD_*` - Enable/disable modules (e.g., `PIP_BUILD_CRYPT=OFF`) + +### Code Generation Tools +- `pip_cmg` - Code model generator (auto-generates code from comments) +- `pip_rc` - Resources compiler (embeds resources into C++ code) +- `pip_tr` - Translation tool (compiles .btf translation files) + +### Linting & Formatting +- **clang-format**: Run `clang-format -i ` or `find . -name "*.cpp" -o -name "*.h" | xargs clang-format -i` +- **Format config**: `.clang-format` (ColumnLimit: 140, IndentWidth: 4, BraceWrapping: Attach) +- **Includes sorting**: Enabled (CaseSensitive, SortIncludes: true) +- **Macro blocks**: `PRIVATE_DEFINITION_START/END`, `STATIC_INITIALIZER_BEGIN/END`, `DECLARE_UNIT_CLASS_BEGIN/END` +- **No Cursor/Copilot rules** found in this repository + +## Code Style Guidelines + +### General +- **Language Standard**: C++11 (CMAKE_CXX_STANDARD 11) +- **File Encoding**: UTF-8 +- **Line Endings**: Unix (LF) +- **Column Limit**: 140 characters + +### Naming Conventions +- **Classes**: `PascalCase` (e.g., `PIObject`, `PIString`) +- **Functions/Methods**: `camelCase` (e.g., `toString()`, `isEmpty()`) +- **Variables**: `camelCase` (e.g., `rowCount`, `isReady`) +- **Constants**: `kPrefixCamelCase` (e.g., `kMaxSize`) +- **Macros**: `UPPER_CASE` (e.g., `PIP_EXPORT`, `NO_COPY_CLASS`) +- **Types**: `PascalCase` with `p` prefix for internal/private (e.g., `PIString_p.h`) + +### File Naming +- Headers: `pi.h` (e.g., `piobject.h`, `pistring.h`) +- Private headers: `pi_p.h` (e.g., `piobject_p.h`) +- Test files: `test.cpp` (e.g., `testpivector2d.cpp`) + +### Comments & Documentation +- Use Doxygen-style comments for all public APIs +- Include `\~english` and `\~russian` translations +- Group related classes/modules with `//! \defgroup` +- Use `\ingroup` to assign files to groups +- Example: + ```cpp + //! \file piobject.h + //! \ingroup Core + //! \~\brief + //! \~english Base object + //! \~russian Базовый класс + ``` + +### Includes +- Order: System headers → PIP headers → Local headers +- Sort alphabetically within groups +- Use `#pragma once` or include guards +- PIP includes use `#include "pi.h"` + +### Formatting (clang-format) +- **Indentation**: 4 spaces (no tabs for code) +- **Braces**: Attach style (`if (x) {`) +- **Pointers/References**: `Type* ptr`, `Type& ref` +- **Templates**: Always break before `>` in nested templates +- **Empty Lines**: Max 2 consecutive empty lines +- **Namespace**: No indentation (`Namespace { ... }`) + +### Error Handling +- Use `PIString` for error messages +- Return bool for success/failure +- Use `assert()` for debug-only checks +- Avoid exceptions (RTTI disabled in some builds) + +### Memory Management +- Prefer stack allocation +- Use `NO_COPY_CLASS(MyClass)` to disable copy +- Implement proper move semantics when needed +- Use `std::unique_ptr`/`std::shared_ptr` sparingly + +### Macros +- PIMETA(...) - Add metadata for code model generator +- PIP_EXPORT - Export/import symbols for DLLs +- NO_COPY_CLASS - Disable copy constructor and operator= +- PRIVATE_DECLARATION - Private implementation macro + +## Testing +- Framework: Google Test (fetched automatically when TESTS=ON) +- Test files: `tests//test.cpp` +- Use `pip_test(module)` macro in `tests/CMakeLists.txt` +- Test discovery via `gtest_discover_tests()` + +### Running Tests +```bash +# Run all tests +ctest + +# Run specific test suite +ctest -R math -V + +# List all available tests +ctest -N + +# Run single test with gtest filter +./build/tests/math/pip_math_test --gtest_filter="Vector2DTest.defaultConstructor*" +``` + +## Module Structure +``` +libs/ +├── main/ # Core modules +│ ├── core/ # Base types, PIObject, PIString +│ ├── thread/ # Threading primitives +│ ├── math/ # Math functions, vectors, matrices +│ └── ... +└── / # Feature modules (fftw, crypt, compress, etc.) +``` + +## Additional Notes +- Project uses custom CMake macros from `cmake/` directory +- Version format: `MAJOR.MINOR.REVISION` (e.g., 5.6.0) +- All files have LGPL license header +- Support for multiple platforms: Windows, Linux, QNX, Android, Apple \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d2d7231..cc063fd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,9 +621,12 @@ if (NOT CROSSTOOLS) endif() if (PIP_BUILD_IO_UTILS) - pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)") + if(PIP_BUILD_CRYPT) + pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)") + else() + pip_module(io_utils "" "PIP I/O support" "" "" "") + endif() endif() - endif() endif() diff --git a/libs/main/core/pibase_macros.h b/libs/main/core/pibase_macros.h index 7896f3ef..4b3d385b 100644 --- a/libs/main/core/pibase_macros.h +++ b/libs/main/core/pibase_macros.h @@ -251,9 +251,11 @@ extern char ** environ; # endif # ifdef MICRO_PIP -# define __PIP_TYPENAME__(T) "?" +# define __PIP_TYPENAME__(T) "?" +# elif defined(__GXX_RTTI__) || defined(__RTTI__) +# define __PIP_TYPENAME__(T) typeid(T).name() # else -# define __PIP_TYPENAME__(T) typeid(T).name() +# define __PIP_TYPENAME__(T) "?" # endif # ifdef CC_GCC diff --git a/libs/main/core/piinit.h b/libs/main/core/piinit.h index 87e31489..d01eac26 100644 --- a/libs/main/core/piinit.h +++ b/libs/main/core/piinit.h @@ -28,7 +28,7 @@ #include "pibase.h" -#ifndef MICRO_PIP +#ifndef PIP_NO_THREADS # include "piincludes.h" @@ -47,6 +47,30 @@ public: static __PIInit_Initializer__ __piinit_initializer__; +#ifdef MICRO_PIP +#ifndef PIINIT_MICRO_STUB_DEFINED +#define PIINIT_MICRO_STUB_DEFINED + +int __PIInit_Initializer__::count_ = 0; +PIInit * __PIInit_Initializer__::__instance__ = nullptr; + +__PIInit_Initializer__::__PIInit_Initializer__() { + count_++; + if (count_ > 1) return; + __instance__ = nullptr; +} + +__PIInit_Initializer__::~__PIInit_Initializer__() { + count_--; + if (count_ > 0) return; + if (__instance__ != nullptr) { + __instance__ = nullptr; + } +} + +#endif +#endif + class PIP_EXPORT PIInit { friend class __PIInit_Initializer__; @@ -88,5 +112,5 @@ private: }; -#endif // MICRO_PIP +#endif // PIP_NO_THREADS #endif // PIINIT_H diff --git a/libs/main/state_machine/pistatemachine_base.h b/libs/main/state_machine/pistatemachine_base.h index 4c1e4c89..a823d852 100644 --- a/libs/main/state_machine/pistatemachine_base.h +++ b/libs/main/state_machine/pistatemachine_base.h @@ -41,7 +41,11 @@ template class Function: public FunctionBase { public: uint formatHash() override { +#if defined(__GXX_RTTI__) || defined(__RTTI__) static uint ret = PIConstChars(typeid(std::function).name()).hash(); +#else + static uint ret = 0; +#endif return ret; } std::function func; diff --git a/libs/main/system/pihidevice.cpp b/libs/main/system/pihidevice.cpp index 78d3f1ff..cf199993 100644 --- a/libs/main/system/pihidevice.cpp +++ b/libs/main/system/pihidevice.cpp @@ -7,12 +7,21 @@ # include "pifile.h" # include "piiostream.h" -# include -# include -# include -# include -# include -# include +# ifdef LINUX +# include +# include +# include +# include +# include +# include +# else +// Stubs for embedded/non-Linux builds +# define EV_SYN 0 +# define EV_KEY 1 +# define EV_REL 2 +# define EV_ABS 3 +# define EVIOCGABS(_v) 0 +# endif #else // clang-format off # undef _WIN32_WINNT @@ -395,6 +404,7 @@ PIVector PIHIDevice::allDevices(bool try_open) { ullong bits = readFile(hd_i.path + file).toULLong(16); // piCout<< PICoutManipulators::Bin << abs; if (bits > 0) { +#ifdef LINUX int fd = ::open(dev.path.dataAscii(), O_RDONLY); if (fd < 0) { // piCout << "Warning: can`t open" << dev.path << errorString(); @@ -419,6 +429,19 @@ PIVector PIHIDevice::allDevices(bool try_open) { } } if (fd >= 0) ::close(fd); +#else + // Stub implementation for non-Linux builds + PIHIDeviceInfo::AxisInfo ai; + ai.is_relative = is_relative; + ai.min = 0; + ai.max = 1024; + for (int bit = 0; bit < 64; ++bit) { + if (checkBit(bits, bit, PIString::fromNumber(bit))) { + ai.data_index = bit; + ret << ai; + } + } +#endif } return ret; }; diff --git a/libs/main/types/pitime.cpp b/libs/main/types/pitime.cpp index 13cea681..66a181e9 100644 --- a/libs/main/types/pitime.cpp +++ b/libs/main/types/pitime.cpp @@ -55,8 +55,21 @@ void piUSleep(int usecs) { # ifdef FREERTOS vTaskDelay(usecs / 1000 / portTICK_PERIOD_MS); # else +# ifdef MICRO_PIP + if (usecs > 0) { + struct timeval start; + gettimeofday(&start, nullptr); + long long elapsed = 0; + while (elapsed < usecs) { + struct timeval now; + gettimeofday(&now, nullptr); + elapsed = (now.tv_sec - start.tv_sec) * 1000000LL + (now.tv_usec - start.tv_usec); + } + } +# else usecs -= PISystemTests::usleep_offset_us; if (usecs > 0) usleep(usecs); +# endif # endif #endif } diff --git a/libs/main/types/pivariantsimple.h b/libs/main/types/pivariantsimple.h index 3dfb6753..65a5d95a 100644 --- a/libs/main/types/pivariantsimple.h +++ b/libs/main/types/pivariantsimple.h @@ -55,12 +55,16 @@ public: } #ifdef MICRO_PIP PIString typeName() const final { - static PIString ret(PIVariant(T()).typeName()); + static PIString ret(PIVariant::fromValue(T()).typeName()); return ret; } #else PIString typeName() const final { +#if defined(__GXX_RTTI__) || defined(__RTTI__) static PIString ret(typeid(T).name()); +#else + static PIString ret("unknown"); +#endif return ret; } #endif