diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml new file mode 100644 index 00000000..91d63d23 --- /dev/null +++ b/.github/workflows/cppcheck.yml @@ -0,0 +1,17 @@ +name: cppcheck static analyser + +on: [push, pull_request] + +jobs: + build: + name: Ubuntu Latest + runs-on: ubuntu-latest + steps: + - run: sudo apt update && sudo apt install -y cppcheck + - name: Checkout ${{ github.ref_name }} + uses: actions/checkout@v4 + - run: git submodule update --init --recursive + - run: mkdir build + - run: cmake -G "Unix Makefiles" -DSQLITECPP_BUILD_LIBRARY=OFF -DSQLITE_ENABLE_COLUMN_METADATA=OFF -DSQLITECPP_RUN_CPPCHECK=ON .. + working-directory: build + - run: cmake --build ./build/ diff --git a/.github/workflows/cpplint.yml b/.github/workflows/cpplint.yml new file mode 100644 index 00000000..125b83dc --- /dev/null +++ b/.github/workflows/cpplint.yml @@ -0,0 +1,16 @@ +name: cpplint C++ linter + +on: [push, pull_request] + +jobs: + build: + name: Ubuntu Latest + runs-on: ubuntu-latest + steps: + - name: Checkout ${{ github.ref_name }} + uses: actions/checkout@v4 + - run: git submodule update --init --recursive + - run: mkdir build + - run: cmake -G "Unix Makefiles" -DSQLITECPP_BUILD_LIBRARY=OFF -DSQLITE_ENABLE_COLUMN_METADATA=OFF -DSQLITECPP_RUN_CPPLINT=ON .. + working-directory: build + - run: cmake --build ./build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index af1f2517..82d148b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,8 +210,12 @@ if (SQLITECPP_INCLUDE_SCRIPT) source_group(scripts FILES ${SQLITECPP_SCRIPT}) endif() -# add sources of the wrapper as a "SQLiteCpp" static library -add_library(SQLiteCpp ${SQLITECPP_SRC} ${SQLITECPP_INC} ${SQLITECPP_DOC} ${SQLITECPP_SCRIPT}) +# Build the "SQLiteCpp" wrapper as a static library +option(SQLITECPP_BUILD_LIBRARY "Build SQLiteCpp wrapper as a library." ON) +if (SQLITECPP_BUILD_LIBRARY) + # Note: add doc and script files to display them in the Visual Studio solution + add_library(SQLiteCpp ${SQLITECPP_SRC} ${SQLITECPP_INC} ${SQLITECPP_DOC} ${SQLITECPP_SCRIPT}) +endif (SQLITECPP_BUILD_LIBRARY) # Options relative to SQLite and SQLiteC++ functions @@ -255,9 +259,11 @@ if (SQLITE_OMIT_LOAD_EXTENSION) target_compile_definitions(SQLiteCpp PUBLIC SQLITE_OMIT_LOAD_EXTENSION) endif (SQLITE_OMIT_LOAD_EXTENSION) -if (UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")) - set_target_properties(SQLiteCpp PROPERTIES COMPILE_FLAGS "-fPIC") -endif (UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")) +if (SQLITECPP_BUILD_LIBRARY) + if (UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")) + set_target_properties(SQLiteCpp PROPERTIES COMPILE_FLAGS "-fPIC") + endif (UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")) +endif (SQLITECPP_BUILD_LIBRARY) option(SQLITECPP_USE_ASAN "Use Address Sanitizer." OFF) if (SQLITECPP_USE_ASAN) @@ -276,16 +282,18 @@ if (SQLITECPP_USE_GCOV) set_target_properties(SQLiteCpp PROPERTIES COMPILE_FLAGS "-fkeep-inline-functions -fkeep-static-functions") endif () -## Build provided copy of SQLite3 C library ## +## Build the SQLite3 C library, or link to the installed one option(SQLITECPP_INTERNAL_SQLITE "Add the internal SQLite3 source to the project." ON) if (SQLITECPP_INTERNAL_SQLITE) - message(STATUS "Compile sqlite3 from source in subdirectory") - option(SQLITE_ENABLE_RTREE "Enable RTree extension when building internal sqlite3 library." OFF) - option(SQLITE_ENABLE_DBSTAT_VTAB "Enable DBSTAT read-only eponymous virtual table extension when building internal sqlite3 library." OFF) - # build the SQLite3 C library (for ease of use/compatibility) versus Linux sqlite3-dev package - add_subdirectory(sqlite3) - target_link_libraries(SQLiteCpp PUBLIC SQLite::SQLite3) + if (SQLITECPP_BUILD_LIBRARY) + message(STATUS "Compile sqlite3 from source in subdirectory") + option(SQLITE_ENABLE_RTREE "Enable RTree extension when building internal sqlite3 library." OFF) + option(SQLITE_ENABLE_DBSTAT_VTAB "Enable DBSTAT read-only eponymous virtual table extension when building internal sqlite3 library." OFF) + # build the SQLite3 C library (for ease of use/compatibility) versus Linux sqlite3-dev package + add_subdirectory(sqlite3) + target_link_libraries(SQLiteCpp PUBLIC SQLite::SQLite3) + endif (SQLITECPP_BUILD_LIBRARY) else (SQLITECPP_INTERNAL_SQLITE) # When using the SQLite codec, we need to link against the sqlcipher lib & include # So this gets the lib & header, and links/includes everything @@ -349,48 +357,52 @@ if (SQLITECPP_DISABLE_EXPANDED_SQL) endif (SQLITECPP_DISABLE_EXPANDED_SQL) # Link target with pthread and dl for Unix -if (UNIX) +if (UNIX AND SQLITECPP_BUILD_LIBRARY) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(SQLiteCpp PUBLIC Threads::Threads ${CMAKE_DL_LIBS}) -endif (UNIX) +endif () # Set includes for target and transitive downstream targets -target_include_directories(SQLiteCpp - PUBLIC - $ - $) +if (SQLITECPP_BUILD_LIBRARY) + target_include_directories(SQLiteCpp + PUBLIC + $ + $) +endif (SQLITECPP_BUILD_LIBRARY) # Allow the library to be installed via "make install" and found with "find_package" -include(GNUInstallDirs) -install(TARGETS SQLiteCpp - EXPORT ${PROJECT_NAME}Targets - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT libraries) -install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT headers FILES_MATCHING REGEX ".*\\.(hpp|h)$") -install(EXPORT ${PROJECT_NAME}Targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) -install(FILES ${PROJECT_SOURCE_DIR}/package.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}) - -include(CMakePackageConfigHelpers) -write_basic_package_version_file( - cmake/${PROJECT_NAME}ConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion) -configure_package_config_file( - cmake/${PROJECT_NAME}Config.cmake.in - cmake/${PROJECT_NAME}Config.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) +if (SQLITECPP_BUILD_LIBRARY) + include(GNUInstallDirs) + install(TARGETS SQLiteCpp + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT libraries) + install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT headers FILES_MATCHING REGEX ".*\\.(hpp|h)$") + install(EXPORT ${PROJECT_NAME}Targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + install(FILES ${PROJECT_SOURCE_DIR}/package.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}) + + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + cmake/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion) + configure_package_config_file( + cmake/${PROJECT_NAME}Config.cmake.in + cmake/${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) +endif (SQLITECPP_BUILD_LIBRARY) # Optional additional targets: -option(SQLITECPP_RUN_CPPLINT "Run cpplint.py tool for Google C++ StyleGuide." ON) +option(SQLITECPP_RUN_CPPLINT "Run cpplint.py tool for Google C++ StyleGuide." OFF) if (SQLITECPP_RUN_CPPLINT) # The minimum version of CMAKE is 3.5, but as of 3.12 the PythonInterp package is deprecated. if(${CMAKE_VERSION} VERSION_LESS "3.12.0") @@ -398,35 +410,35 @@ if (SQLITECPP_RUN_CPPLINT) if (PYTHONINTERP_FOUND) # add a cpplint target to the "all" target add_custom_target(SQLiteCpp_cpplint - ALL - COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/cpplint.py ${CPPLINT_ARG_OUTPUT} ${CPPLINT_ARG_VERBOSE} ${CPPLINT_ARG_LINELENGTH} ${SQLITECPP_SRC} ${SQLITECPP_INC} + ALL + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/cpplint.py ${CPPLINT_ARG_OUTPUT} ${CPPLINT_ARG_VERBOSE} ${CPPLINT_ARG_LINELENGTH} ${SQLITECPP_SRC} ${SQLITECPP_INC} ) endif (PYTHONINTERP_FOUND) else() find_package(Python) - if (PYTHON_INTERPRETER_FOUND) + if (Python_Interpreter_FOUND) # add a cpplint target to the "all" target add_custom_target(SQLiteCpp_cpplint - ALL - COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/cpplint.py ${CPPLINT_ARG_OUTPUT} ${CPPLINT_ARG_VERBOSE} ${CPPLINT_ARG_LINELENGTH} ${SQLITECPP_SRC} ${SQLITECPP_INC} + ALL + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/cpplint.py ${CPPLINT_ARG_OUTPUT} ${CPPLINT_ARG_VERBOSE} ${CPPLINT_ARG_LINELENGTH} ${SQLITECPP_SRC} ${SQLITECPP_INC} ) - endif (PYTHON_INTERPRETER_FOUND) + endif (Python_Interpreter_FOUND) endif() else (SQLITECPP_RUN_CPPLINT) message(STATUS "SQLITECPP_RUN_CPPLINT OFF") endif (SQLITECPP_RUN_CPPLINT) -option(SQLITECPP_RUN_CPPCHECK "Run cppcheck C++ static analysis tool." ON) +option(SQLITECPP_RUN_CPPCHECK "Run cppcheck C++ static analysis tool." OFF) if (SQLITECPP_RUN_CPPCHECK) find_program(CPPCHECK_EXECUTABLE NAMES cppcheck) if (CPPCHECK_EXECUTABLE) # add a cppcheck target to the "all" target add_custom_target(SQLiteCpp_cppcheck ALL - COMMAND ${CPPCHECK_EXECUTABLE} -j 8 cppcheck --enable=style --quiet ${CPPCHECK_ARG_TEMPLATE} ${PROJECT_SOURCE_DIR}/src + COMMAND ${CPPCHECK_EXECUTABLE} -j 8 cppcheck --enable=style --quiet ${CPPCHECK_ARG_TEMPLATE} ${PROJECT_SOURCE_DIR}/src --error-exitcode=2 ) execute_process(COMMAND "${CPPCHECK_EXECUTABLE}" --version OUTPUT_VARIABLE CPPCHECK_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "Found Cppcheck: ${CPPCHECK_EXECUTABLE} ${CPPCHECK_VERSION}") + message(STATUS "Found Cppcheck: ${CPPCHECK_EXECUTABLE} (found version ${CPPCHECK_VERSION})") else (CPPCHECK_EXECUTABLE) message(STATUS "Could NOT find cppcheck") endif (CPPCHECK_EXECUTABLE) @@ -516,4 +528,6 @@ else (SQLITECPP_BUILD_TESTS) endif (SQLITECPP_BUILD_TESTS) # API version for SQLiteCpp shared library. -set_property(TARGET SQLiteCpp PROPERTY SOVERSION 0) +if (SQLITECPP_BUILD_LIBRARY) + set_property(TARGET SQLiteCpp PROPERTY SOVERSION 0) +endif (SQLITECPP_BUILD_LIBRARY) diff --git a/cpplint.py b/cpplint.py index 8fecfa99..91b6cc51 100755 --- a/cpplint.py +++ b/cpplint.py @@ -47,11 +47,19 @@ import math # for log import os import re -import sre_compile import string import sys import unicodedata +# sre_compile will be/has been removed in Python 3.13 +# use re._compiler instead +# Refs: https://github.com/python/cpython/issues/105456 +# Refs: https://github.com/python/cpython/issues/91308 +try: + srecompile = re._compiler.compile +except AttributeError: + import sre_compile + srecompile = sre_compile.compile try: xrange(0,1) @@ -506,7 +514,7 @@ def Match(pattern, s): # performance reasons; factoring it out into a separate function turns out # to be noticeably expensive. if pattern not in _regexp_compile_cache: - _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + _regexp_compile_cache[pattern] = srecompile(pattern) return _regexp_compile_cache[pattern].match(s) @@ -524,14 +532,14 @@ def ReplaceAll(pattern, rep, s): string with replacements made (or original string if no replacements) """ if pattern not in _regexp_compile_cache: - _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + _regexp_compile_cache[pattern] = srecompile(pattern) return _regexp_compile_cache[pattern].sub(rep, s) def Search(pattern, s): """Searches the string for the pattern, caching the compiled regexp.""" if pattern not in _regexp_compile_cache: - _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + _regexp_compile_cache[pattern] = srecompile(pattern) return _regexp_compile_cache[pattern].search(s) @@ -879,7 +887,7 @@ def RepositoryName(self): If we have a real absolute path name here we can try to do something smart: detecting the root of the checkout and truncating /path/to/checkout from the name so that we get header guards that don't include things like - "C:\Documents and Settings\..." or "/home/username/..." in them and thus + "C:/Documents and Settings/..." or "/home/username/..." in them and thus people on different computers who have checked the source out to different locations won't see bogus errors. """ @@ -2707,7 +2715,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): line = clean_lines.elided[linenum] # get rid of comments and strings # Don't try to do spacing checks for operator methods - line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line) + line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', r'operator\(', line) # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". # Otherwise not. Note we only check for non-spaces on *both* sides; @@ -2909,8 +2917,8 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): # In range-based for, we wanted spaces before and after the colon, but # not around "::" tokens that might appear. - if (Search('for *\(.*[^:]:[^: ]', line) or - Search('for *\(.*[^: ]:[^:]', line)): + if (Search(r'for *\(.*[^:]:[^: ]', line) or + Search(r'for *\(.*[^: ]:[^:]', line)): error(filename, linenum, 'whitespace/forcolon', 2, 'Missing space around colon in range-based for loop') @@ -4799,8 +4807,8 @@ def main(): ProcessFile(filename, _cpplint_state.verbose_level) _cpplint_state.PrintErrorCounts() - # SRombauts: do not break build for cpplint style warnings - #sys.exit(_cpplint_state.error_count > 0) + # SRombauts: break the build for cpplint style warnings + sys.exit(_cpplint_state.error_count > 0) if __name__ == '__main__':