liburlparser 2.0.0__tar.gz → 2.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. {liburlparser-2.0.0 → liburlparser-2.1.0}/.github/workflows/orchestrator.yml +15 -0
  2. {liburlparser-2.0.0 → liburlparser-2.1.0}/.github/workflows/wheels.yml +1 -1
  3. {liburlparser-2.0.0 → liburlparser-2.1.0}/CMakeLists.txt +84 -38
  4. {liburlparser-2.0.0 → liburlparser-2.1.0}/PKG-INFO +91 -25
  5. {liburlparser-2.0.0 → liburlparser-2.1.0}/README.md +90 -24
  6. liburlparser-2.1.0/benchmarks/CMakeLists.txt +148 -0
  7. liburlparser-2.1.0/benchmarks/OPTIMIZATION_NOTES.md +334 -0
  8. {liburlparser-2.0.0 → liburlparser-2.1.0}/benchmarks/README.md +24 -3
  9. liburlparser-2.1.0/benchmarks/cmake/Download.cmake +26 -0
  10. liburlparser-2.1.0/benchmarks/corpus/.gitignore +3 -0
  11. liburlparser-2.1.0/benchmarks/corpus/generate_corpus.py +71 -0
  12. {liburlparser-2.0.0 → liburlparser-2.1.0}/benchmarks/cpp/CMakeLists.txt +2 -2
  13. liburlparser-2.1.0/benchmarks/cpp/abspath_fix_verification/README.md +41 -0
  14. liburlparser-2.1.0/benchmarks/cpp/abspath_fix_verification/fair_compare.cpp +81 -0
  15. liburlparser-2.1.0/benchmarks/cpp/bench.cpp +605 -0
  16. liburlparser-2.1.0/benchmarks/cpp/psl_structures/README.md +95 -0
  17. liburlparser-2.1.0/benchmarks/cpp/psl_structures/psl_structure_comparison.cpp +713 -0
  18. liburlparser-2.1.0/benchmarks/python/CMakeLists.txt +77 -0
  19. liburlparser-2.1.0/benchmarks/python/bench.py +523 -0
  20. liburlparser-2.1.0/benchmarks/python/binding_fast_path_ab.py +50 -0
  21. {liburlparser-2.0.0 → liburlparser-2.1.0}/benchmarks/python/requirements.txt +5 -0
  22. liburlparser-2.1.0/benchmarks/report/CMakeLists.txt +53 -0
  23. liburlparser-2.1.0/benchmarks/report/generate_report.py +214 -0
  24. liburlparser-2.1.0/benchmarks/report/template.html.jinja2 +192 -0
  25. liburlparser-2.1.0/benchmarks/results/report.html +918 -0
  26. liburlparser-2.1.0/cmake/liburlparserConfig.cmake +26 -0
  27. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/index.html.in +5 -2
  28. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/page.html.in +3 -0
  29. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/section.html.in +3 -0
  30. liburlparser-2.1.0/examples/find_liburlparser_via_python/CMakeLists.txt +26 -0
  31. liburlparser-2.1.0/examples/find_liburlparser_via_python/main.cpp +13 -0
  32. {liburlparser-2.0.0 → liburlparser-2.1.0}/include/urlparser.h +301 -7
  33. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/bindings/python/binding_py.cpp +264 -7
  34. liburlparser-2.1.0/src/bindings/python/liburlparser/__init__.py +45 -0
  35. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/bindings/python/liburlparser/__main__.py +16 -1
  36. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/bindings/python/liburlparser/core.py +6 -1
  37. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/public_suffix_list.dat +1129 -442
  38. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/urlparser.cpp +1033 -16
  39. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/cpp/CMakeLists.txt +29 -0
  40. liburlparser-2.1.0/tests/cpp/fuzz_abspath.cpp +113 -0
  41. liburlparser-2.1.0/tests/cpp/perf_regression_guard.cpp +129 -0
  42. liburlparser-2.1.0/tests/cpp/test_idna.cpp +62 -0
  43. liburlparser-2.1.0/tests/cpp/test_normalize.cpp +234 -0
  44. liburlparser-2.1.0/tests/cpp/test_percent_codec.cpp +82 -0
  45. liburlparser-2.1.0/tests/cpp/test_resolve.cpp +74 -0
  46. liburlparser-2.1.0/tests/cpp/test_scp_url.cpp +93 -0
  47. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/cpp/test_url.cpp +57 -0
  48. liburlparser-2.1.0/tests/python/test_idna.py +43 -0
  49. liburlparser-2.1.0/tests/python/test_normalize.py +146 -0
  50. liburlparser-2.1.0/tests/python/test_percent_codec.py +60 -0
  51. liburlparser-2.1.0/tests/python/test_resolve.py +39 -0
  52. liburlparser-2.1.0/tests/python/test_scp_url.py +66 -0
  53. liburlparser-2.0.0/benchmarks/CMakeLists.txt +0 -120
  54. liburlparser-2.0.0/benchmarks/OPTIMIZATION_NOTES.md +0 -224
  55. liburlparser-2.0.0/benchmarks/cpp/bench.cpp +0 -248
  56. liburlparser-2.0.0/benchmarks/python/CMakeLists.txt +0 -33
  57. liburlparser-2.0.0/benchmarks/python/bench.py +0 -242
  58. liburlparser-2.0.0/src/bindings/python/liburlparser/__init__.py +0 -14
  59. {liburlparser-2.0.0 → liburlparser-2.1.0}/.clang-format +0 -0
  60. {liburlparser-2.0.0 → liburlparser-2.1.0}/.github/workflows/cmake.yml +0 -0
  61. {liburlparser-2.0.0 → liburlparser-2.1.0}/.github/workflows/process_release.py +0 -0
  62. {liburlparser-2.0.0 → liburlparser-2.1.0}/.github/workflows/release_template.md +0 -0
  63. {liburlparser-2.0.0 → liburlparser-2.1.0}/.gitignore +0 -0
  64. {liburlparser-2.0.0 → liburlparser-2.1.0}/ARCHITECTURE.md +0 -0
  65. {liburlparser-2.0.0 → liburlparser-2.1.0}/LICENSE +0 -0
  66. {liburlparser-2.0.0 → liburlparser-2.1.0}/benchmarks/.gitignore +0 -0
  67. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/DynamicVersion.cmake +0 -0
  68. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/EmbedFile.cmake +0 -0
  69. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/FixLCovPaths.cmake +0 -0
  70. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/GenerateIframe.cmake +0 -0
  71. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/PublicSuffixList.cmake +0 -0
  72. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/PyProject.cmake +0 -0
  73. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/coverage_iframe.html.in +0 -0
  74. {liburlparser-2.0.0 → liburlparser-2.1.0}/cmake/utils/embedded_string.in.h +0 -0
  75. {liburlparser-2.0.0 → liburlparser-2.1.0}/conda.recipe/meta.yaml +0 -0
  76. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/CMakeLists.txt +0 -0
  77. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/CreateDocs.cmake +0 -0
  78. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/InjectComment.cmake +0 -0
  79. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/UrlParserPages.cmake +0 -0
  80. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cli/examples.md +0 -0
  81. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cli/index.md +0 -0
  82. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cli/installation.md +0 -0
  83. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cli/options.md +0 -0
  84. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/convert_page.py +0 -0
  85. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/CreateDocs.cmake +0 -0
  86. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/Doxyfile.in +0 -0
  87. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/footer.html.in +0 -0
  88. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/header.html +0 -0
  89. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/images/interface-arch.svg +0 -0
  90. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/images/url-parsing-process.svg +0 -0
  91. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/cpp/mainpage.md +0 -0
  92. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/images/liburlparser-sq.txt +0 -0
  93. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/images/logo/liburlparser-logo-1.svg +0 -0
  94. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/images/logo/liburlparser-logo-2.svg +0 -0
  95. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/initial_comment.in +0 -0
  96. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/CreateDocs.cmake +0 -0
  97. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/api/host.md +0 -0
  98. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/api/psl.md +0 -0
  99. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/api/reference.rst +0 -0
  100. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/api/url.md +0 -0
  101. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/conf.py +0 -0
  102. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/examples.md +0 -0
  103. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/index.md +0 -0
  104. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/installation.md +0 -0
  105. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/performance.md +0 -0
  106. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/usage/advanced.md +0 -0
  107. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/usage/basic.md +0 -0
  108. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/docs/usage/cli.md +0 -0
  109. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/python/mkdocs.yml +0 -0
  110. {liburlparser-2.0.0 → liburlparser-2.1.0}/docs/urlparser-docs.css +0 -0
  111. {liburlparser-2.0.0 → liburlparser-2.1.0}/examples/common.h +0 -0
  112. {liburlparser-2.0.0 → liburlparser-2.1.0}/examples/main.cpp +0 -0
  113. {liburlparser-2.0.0 → liburlparser-2.1.0}/pyproject.toml +0 -0
  114. {liburlparser-2.0.0 → liburlparser-2.1.0}/requirements-dev.txt +0 -0
  115. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/ankerl/LICENSE +0 -0
  116. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/ankerl/README.md +0 -0
  117. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/ankerl/stl.h +0 -0
  118. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/ankerl/unordered_dense.h +0 -0
  119. {liburlparser-2.0.0 → liburlparser-2.1.0}/src/bindings/python/liburlparser/utils.py +0 -0
  120. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/CMakeLists.txt +0 -0
  121. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/coverage_dashboard.html.in +0 -0
  122. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/cpp/common.h +0 -0
  123. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/cpp/test_host.cpp +0 -0
  124. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/data/host_data.csv +0 -0
  125. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/data/url_data.csv +0 -0
  126. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/genhtml.css +0 -0
  127. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/python/CMakeLists.txt +0 -0
  128. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/python/test_cli_subprocess.py +0 -0
  129. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/python/test_extra.py +0 -0
  130. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/python/test_host.py +0 -0
  131. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/python/test_memory.py +0 -0
  132. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/python/test_url.py +0 -0
  133. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/utest/utest.h +0 -0
  134. {liburlparser-2.0.0 → liburlparser-2.1.0}/tests/utest/utest_main.cxx +0 -0
  135. {liburlparser-2.0.0 → liburlparser-2.1.0}/version.py +0 -0
@@ -99,6 +99,9 @@ jobs:
99
99
  id-token: write
100
100
 
101
101
  steps:
102
+ - name: Checkout repository
103
+ uses: actions/checkout@v4
104
+
102
105
  - name: Download documentation artifact
103
106
  uses: actions/download-artifact@v4
104
107
  with:
@@ -111,6 +114,18 @@ jobs:
111
114
  name: cmake-coverage-report
112
115
  path: ./pages/coverage
113
116
 
117
+ # Benchmarks are NOT run in CI: the report is generated locally
118
+ # (cmake --build <dir> --target urlparser_benchmarks_report) and committed
119
+ # as benchmarks/results/report.html. CI only publishes it, as /benchmarks/.
120
+ - name: Add benchmark report
121
+ run: |
122
+ if [ ! -f benchmarks/results/report.html ]; then
123
+ echo "::error::benchmarks/results/report.html is missing - generate it locally and commit it"
124
+ exit 1
125
+ fi
126
+ mkdir -p pages/benchmarks
127
+ cp benchmarks/results/report.html pages/benchmarks/index.html
128
+
114
129
  - name: List pages directory
115
130
  run: find pages -maxdepth 2
116
131
 
@@ -53,7 +53,7 @@ jobs:
53
53
  - uses: actions/checkout@v4
54
54
 
55
55
  - name: Build wheels
56
- uses: pypa/cibuildwheel@v2.21.3
56
+ uses: pypa/cibuildwheel@v4.2.1
57
57
  env:
58
58
  MACOSX_DEPLOYMENT_TARGET: "10.13"
59
59
  CIBW_ARCHS_MACOS: universal2
@@ -40,15 +40,7 @@ endif()
40
40
 
41
41
  find_package(Python3 REQUIRED COMPONENTS Interpreter)
42
42
 
43
- # --- httpp local patch --------------------------------------------------
44
- # Only treat this as "liburlparser is the scikit-build-core package being
45
- # installed" when SKBUILD_PROJECT_NAME actually IS liburlparser. Without
46
- # this guard, vendoring liburlparser as a subdirectory of another
47
- # scikit-build-core project (e.g. httpp) makes it wrongly think it's the
48
- # top-level package and try to build its own nanobind bindings, which
49
- # fails when nanobind isn't installed (it isn't a dependency of the
50
- # parent project at all). See src/third_party/README.md for details.
51
- if(DEFINED SKBUILD AND SKBUILD_PROJECT_NAME STREQUAL PROJECT_NAME)
43
+ if(DEFINED SKBUILD)
52
44
  set(PYTHON_PROJECT_NAME "${SKBUILD_PROJECT_NAME}")
53
45
  elseif(BUILD_PYTHON)
54
46
  set(PYTHON_PROJECT_NAME "${CMAKE_BINARY_DIR}")
@@ -104,6 +96,44 @@ embed_file_as_string(
104
96
  )
105
97
 
106
98
 
99
+ # --- C++ core library (static) ---
100
+ # Built in every mode (including scikit-build), so the Python extension
101
+ # links the very same library that gets shipped to C++ consumers.
102
+ # Install layout: the wheel carries include/, lib/ and cmake/ inside the
103
+ # `liburlparser` package (nanobind/pybind11 pattern, see get_cmake_dir() in
104
+ # the Python package); a plain `cmake --install` uses the usual prefix layout.
105
+ if(DEFINED SKBUILD)
106
+ set(_urlparser_lib_dest liburlparser/lib)
107
+ set(_urlparser_inc_dest liburlparser/include)
108
+ set(_urlparser_cmake_dest liburlparser/cmake)
109
+ else()
110
+ set(_urlparser_lib_dest lib)
111
+ set(_urlparser_inc_dest include)
112
+ set(_urlparser_cmake_dest lib/cmake/liburlparser)
113
+ endif()
114
+
115
+ add_library(urlparser STATIC ${SOURCES})
116
+ # The public target is `urlparser::urlparser` - the same name whether the
117
+ # library comes from FetchContent/add_subdirectory (this alias) or from an
118
+ # installed package (find_package(liburlparser), exported below).
119
+ add_library(urlparser::urlparser ALIAS urlparser)
120
+
121
+ set_target_properties(urlparser PROPERTIES
122
+ POSITION_INDEPENDENT_CODE ON # linked into the Python extension
123
+ CXX_VISIBILITY_PRESET hidden
124
+ VISIBILITY_INLINES_HIDDEN ON
125
+ EXPORT_NAME urlparser # installed as urlparser::urlparser (see install(EXPORT))
126
+ OUTPUT_NAME urlparser # liburlparser.a / urlparser.lib
127
+ )
128
+ target_include_directories(urlparser
129
+ PUBLIC
130
+ $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
131
+ $<INSTALL_INTERFACE:${_urlparser_inc_dest}>
132
+ PRIVATE
133
+ ${PROJECT_SOURCE_DIR}/src
134
+ ${GENERATED_HEADERS_DIR})
135
+
136
+
107
137
  if(DEFINED PYTHON_PROJECT_NAME)
108
138
  # Try to import all Python components potentially needed by nanobind
109
139
  #set(Python3_FIND_STRATEGY LOCATION)
@@ -140,10 +170,10 @@ if(DEFINED PYTHON_PROJECT_NAME)
140
170
  ${NB_ABI_ARGS}
141
171
 
142
172
  # Source code goes here
143
- ${PROJECT_SOURCE_DIR}/src/bindings/python/binding_py.cpp ${SOURCES}
173
+ ${PROJECT_SOURCE_DIR}/src/bindings/python/binding_py.cpp
144
174
  )
145
175
 
146
- target_include_directories(${NB_MODULE} PRIVATE include src ${GENERATED_HEADERS_DIR})
176
+ target_link_libraries(${NB_MODULE} PRIVATE urlparser)
147
177
 
148
178
  if(DEFINED SKBUILD)
149
179
  install(TARGETS ${NB_MODULE}
@@ -157,37 +187,53 @@ if(DEFINED PYTHON_PROJECT_NAME)
157
187
  endif()
158
188
  endif()
159
189
 
160
- if(DEFINED SKBUILD AND SKBUILD_PROJECT_NAME STREQUAL PROJECT_NAME)
161
- # (see the httpp local-patch comment above) only early-return here when
162
- # liburlparser itself is the package scikit-build-core is installing —
163
- # not when it's vendored as a subdirectory of another project.
190
+ # --- install: find_package(liburlparser CONFIG) -> urlparser::urlparser ---
191
+ include(CMakePackageConfigHelpers)
192
+ install(TARGETS urlparser EXPORT liburlparserTargets
193
+ ARCHIVE DESTINATION ${_urlparser_lib_dest}
194
+ LIBRARY DESTINATION ${_urlparser_lib_dest})
195
+ install(DIRECTORY include/ DESTINATION ${_urlparser_inc_dest})
196
+ install(EXPORT liburlparserTargets
197
+ FILE liburlparserTargets.cmake
198
+ NAMESPACE urlparser::
199
+ DESTINATION ${_urlparser_cmake_dest})
200
+
201
+ # urlparser_LIB_PATH / urlparser_INCLUDE_PATH for consumers that want plain
202
+ # paths. The exact artifact name (liburlparser.a, urlparser.lib, ...) is only
203
+ # known to the generator, so the file is produced with file(GENERATE) - the
204
+ # generator expression is resolved when the build system is generated, and the
205
+ # result is installed next to the package config. Paths are written relative
206
+ # to the installed file itself, so the package stays relocatable.
207
+ file(RELATIVE_PATH _urlparser_rel_lib "/_/${_urlparser_cmake_dest}" "/_/${_urlparser_lib_dest}")
208
+ file(RELATIVE_PATH _urlparser_rel_inc "/_/${_urlparser_cmake_dest}" "/_/${_urlparser_inc_dest}")
209
+ string(REGEX REPLACE "/+$" "" _urlparser_rel_lib "${_urlparser_rel_lib}")
210
+ string(REGEX REPLACE "/+$" "" _urlparser_rel_inc "${_urlparser_rel_inc}")
211
+ file(GENERATE
212
+ OUTPUT ${PROJECT_BINARY_DIR}/liburlparserPaths.cmake
213
+ CONTENT
214
+ "# Generated by liburlparser's CMakeLists.txt - do not edit.
215
+ get_filename_component(urlparser_LIB_PATH
216
+ \"\${CMAKE_CURRENT_LIST_DIR}/${_urlparser_rel_lib}/$<TARGET_FILE_NAME:urlparser>\" ABSOLUTE)
217
+ get_filename_component(urlparser_INCLUDE_PATH
218
+ \"\${CMAKE_CURRENT_LIST_DIR}/${_urlparser_rel_inc}\" ABSOLUTE)
219
+ ")
220
+
221
+ write_basic_package_version_file(
222
+ ${PROJECT_BINARY_DIR}/liburlparserConfigVersion.cmake
223
+ VERSION ${PROJECT_VERSION}
224
+ COMPATIBILITY SameMajorVersion)
225
+ install(FILES
226
+ ${PROJECT_SOURCE_DIR}/cmake/liburlparserConfig.cmake
227
+ ${PROJECT_BINARY_DIR}/liburlparserPaths.cmake
228
+ ${PROJECT_BINARY_DIR}/liburlparserConfigVersion.cmake
229
+ DESTINATION ${_urlparser_cmake_dest})
230
+
231
+ if(DEFINED SKBUILD)
164
232
  RETURN()
165
233
  endif()
166
234
 
167
-
168
-
169
- add_library(urlparser STATIC ${SOURCES})
170
- add_library(url::base ALIAS urlparser)
171
- target_include_directories(urlparser PRIVATE ${GENERATED_HEADERS_DIR})
172
-
173
-
174
- target_include_directories(urlparser
175
- PUBLIC
176
- ${PROJECT_SOURCE_DIR}/include
177
- PRIVATE
178
- ${PROJECT_SOURCE_DIR}/src)
179
-
180
-
181
235
  add_executable(example examples/main.cpp)
182
- target_link_libraries(example PRIVATE url::base)
183
-
184
- install(TARGETS urlparser
185
- LIBRARY DESTINATION lib
186
- ARCHIVE DESTINATION lib
187
- INCLUDES DESTINATION include
188
- )
189
-
190
-
236
+ target_link_libraries(example PRIVATE urlparser::urlparser)
191
237
 
192
238
  enable_testing()
193
239
  find_package(Threads REQUIRED)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: liburlparser
3
- Version: 2.0.0
3
+ Version: 2.1.0
4
4
  Summary: Fastest Url parser in the world
5
5
  Author-Email: Mohammad Raziei <mohammadraziei1375@gmail.com>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
39
39
  [![forks - liburlparser](https://img.shields.io/github/forks/mohammadraziei/liburlparser?style=social)](https://github.com/mohammadraziei/liburlparser)
40
40
 
41
41
  [![PyPi](https://img.shields.io/pypi/v/liburlparser.svg)](https://pypi.org/project/liburlparser/)
42
- ![Python](https://img.shields.io/badge/Python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue)
42
+ ![Python](https://img.shields.io/badge/Python-3.10%20%7C%203.11%20%7C%203.12-blue)
43
43
  ![Cpp](https://img.shields.io/badge/C++-17-blue)
44
44
 
45
45
  [![GitHub release](https://img.shields.io/github/release/mohammadraziei/liburlparser?include_prereleases=&sort=semver&color=purple)](https://github.com/mohammadraziei/liburlparser/releases/)
@@ -240,49 +240,102 @@ you can see all methods in python we can use in c++ very easily
240
240
 
241
241
  ## Installation
242
242
 
243
- ### C++:
243
+ ### C++
244
+
245
+ Requires a C++17 compiler and CMake >= 3.19. The library is a static library plus one header (`urlparser.h`),
246
+ and its CMake target is **`urlparser::urlparser`** - the same name no matter how you get it:
247
+
248
+ #### 1. FetchContent
244
249
 
245
- #### build steps:
250
+ ```cmake
251
+ include(FetchContent)
252
+ FetchContent_Declare(
253
+ liburlparser
254
+ GIT_REPOSITORY https://github.com/mohammadraziei/liburlparser.git
255
+ GIT_TAG master
256
+ )
257
+ FetchContent_MakeAvailable(liburlparser)
258
+
259
+ target_link_libraries(my_app PRIVATE urlparser::urlparser)
260
+ ```
261
+
262
+ #### 2. From the pip package
263
+
264
+ The Python wheel also ships the compiled C++ library, its header and a CMake
265
+ package config (same idea as `python -m nanobind --cmake_dir`), so a C++
266
+ project can use a plain `pip install liburlparser` without building anything:
267
+
268
+ ```cmake
269
+ find_package(Python3 REQUIRED COMPONENTS Interpreter)
270
+ execute_process(
271
+ COMMAND ${Python3_EXECUTABLE} -m liburlparser --cmake-dir
272
+ OUTPUT_VARIABLE liburlparser_DIR
273
+ OUTPUT_STRIP_TRAILING_WHITESPACE
274
+ COMMAND_ERROR_IS_FATAL ANY)
275
+
276
+ find_package(liburlparser CONFIG REQUIRED)
277
+ target_link_libraries(my_app PRIVATE urlparser::urlparser)
278
+ ```
279
+
280
+ For build systems that prefer plain paths over the target, `find_package` also sets:
281
+
282
+ | Variable | Value |
283
+ | ------------------------ | ------------------------------------------------------------------ |
284
+ | `urlparser_LIB_PATH` | full path of the compiled library (`liburlparser.a`, `urlparser.lib`, ...) |
285
+ | `urlparser_INCLUDE_PATH` | directory containing `urlparser.h` |
286
+
287
+ The same locations are available from the command line and from Python:
246
288
 
247
289
  ```sh
248
- # 1. Clone the repository with submodules (recursive)
249
- # --recursive is essential to download third-party libs like googletest
250
- git clone --recursive https://github.com/mohammadraziei/liburlparser
251
- cd liburlparser
290
+ python -m liburlparser --cmake-dir # directory with liburlparserConfig.cmake
291
+ python -m liburlparser --include-dir # directory with urlparser.h
292
+ python -m liburlparser --lib-dir # directory with the compiled library
293
+ ```
294
+
295
+ ```python
296
+ import liburlparser
297
+ liburlparser.get_cmake_dir(), liburlparser.get_include_dir(), liburlparser.get_lib_dir()
298
+ ```
252
299
 
253
- # 2. Configure the project
254
- # -B build tells CMake to create a 'build' directory and generate files there
255
- cmake -B build
300
+ A complete example project is in
301
+ [examples/find_liburlparser_via_python](examples/find_liburlparser_via_python).
256
302
 
257
- # 3. Build the project
258
- # --build abstracts the underlying build tool (Make, Ninja, MSBuild, etc.)
259
- cmake --build build --config Debug
303
+ #### 3. Build and install from source
260
304
 
261
- # 4. Run examples
262
- # Note: On Windows, the path might be ./build/Debug/example.exe
305
+ ```sh
306
+ git clone https://github.com/mohammadraziei/liburlparser
307
+ cd liburlparser
308
+
309
+ # configure and build (-B creates the 'build' directory)
310
+ cmake -B build -DCMAKE_BUILD_TYPE=Release
311
+ cmake --build build
312
+
313
+ # run the example (on Windows with multi-config generators: ./build/Release/example.exe)
263
314
  ./build/example
264
315
 
265
- # 5. Make install
266
- # --install handles the installation process
267
- sudo cmake --install build
316
+ # install the library, header and CMake package (add --prefix <dir> to choose where)
317
+ cmake --install build
318
+ ```
319
+
320
+ Then, in your project (add `-DCMAKE_PREFIX_PATH=<prefix>` if you used a custom prefix):
321
+
322
+ ```cmake
323
+ find_package(liburlparser CONFIG REQUIRED)
324
+ target_link_libraries(my_app PRIVATE urlparser::urlparser)
268
325
  ```
269
326
 
270
327
  ### Python and Command Line:
271
328
 
272
- Be aware that it required `python>=3.8`
329
+ Be aware that it requires `python>=3.10`
273
330
 
274
331
  #### Installation
275
332
 
276
333
  ###### from source
277
334
 
278
- To install from source, you must ensure all submodules are cloned:
279
-
280
335
  ```bash
281
- # 1. Clone recursively to get third-party dependencies
282
- git clone --recursive https://github.com/mohammadraziei/liburlparser
336
+ git clone https://github.com/mohammadraziei/liburlparser
283
337
  cd liburlparser
284
338
 
285
- # 2. Install using pip
286
339
  pip install .
287
340
 
288
341
  # Optional: If you want to see build logs
@@ -314,6 +367,18 @@ pip install ./liburlparser
314
367
 
315
368
  ### Performance
316
369
 
370
+ Up-to-date, reproducible results for both C++ and Python (compared against other libraries)
371
+ are on the **[Benchmarks page](https://mohammadraziei.github.io/liburlparser/benchmarks/)**.
372
+ The report is generated locally and published with the documentation:
373
+
374
+ ```sh
375
+ cmake -S benchmarks -B build-bench -DCMAKE_BUILD_TYPE=Release
376
+ cmake --build build-bench --target urlparser_benchmarks_report
377
+ # -> benchmarks/results/report.html
378
+ ```
379
+
380
+ The two tables below are the original measurements from March 2022.
381
+
317
382
  #### Extract From Host
318
383
 
319
384
  Tests were run on a file containing 10 million random domains from various top-level domains (Mar. 13rd 2022)
@@ -354,5 +419,6 @@ Project Link:
354
419
 
355
420
  - [https://github.com/mohammadraziei/liburlparser](https://github.com/mohammadraziei/liburlparser)
356
421
  - [https://pypi.org/project/liburlparser](https://pypi.org/project/liburlparser)
422
+ - [Documentation](https://mohammadraziei.github.io/liburlparser/) and [Benchmarks](https://mohammadraziei.github.io/liburlparser/benchmarks/)
357
423
 
358
424
  [license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=flat-square
@@ -15,7 +15,7 @@
15
15
  [![forks - liburlparser](https://img.shields.io/github/forks/mohammadraziei/liburlparser?style=social)](https://github.com/mohammadraziei/liburlparser)
16
16
 
17
17
  [![PyPi](https://img.shields.io/pypi/v/liburlparser.svg)](https://pypi.org/project/liburlparser/)
18
- ![Python](https://img.shields.io/badge/Python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue)
18
+ ![Python](https://img.shields.io/badge/Python-3.10%20%7C%203.11%20%7C%203.12-blue)
19
19
  ![Cpp](https://img.shields.io/badge/C++-17-blue)
20
20
 
21
21
  [![GitHub release](https://img.shields.io/github/release/mohammadraziei/liburlparser?include_prereleases=&sort=semver&color=purple)](https://github.com/mohammadraziei/liburlparser/releases/)
@@ -216,49 +216,102 @@ you can see all methods in python we can use in c++ very easily
216
216
 
217
217
  ## Installation
218
218
 
219
- ### C++:
219
+ ### C++
220
+
221
+ Requires a C++17 compiler and CMake >= 3.19. The library is a static library plus one header (`urlparser.h`),
222
+ and its CMake target is **`urlparser::urlparser`** - the same name no matter how you get it:
223
+
224
+ #### 1. FetchContent
220
225
 
221
- #### build steps:
226
+ ```cmake
227
+ include(FetchContent)
228
+ FetchContent_Declare(
229
+ liburlparser
230
+ GIT_REPOSITORY https://github.com/mohammadraziei/liburlparser.git
231
+ GIT_TAG master
232
+ )
233
+ FetchContent_MakeAvailable(liburlparser)
234
+
235
+ target_link_libraries(my_app PRIVATE urlparser::urlparser)
236
+ ```
237
+
238
+ #### 2. From the pip package
239
+
240
+ The Python wheel also ships the compiled C++ library, its header and a CMake
241
+ package config (same idea as `python -m nanobind --cmake_dir`), so a C++
242
+ project can use a plain `pip install liburlparser` without building anything:
243
+
244
+ ```cmake
245
+ find_package(Python3 REQUIRED COMPONENTS Interpreter)
246
+ execute_process(
247
+ COMMAND ${Python3_EXECUTABLE} -m liburlparser --cmake-dir
248
+ OUTPUT_VARIABLE liburlparser_DIR
249
+ OUTPUT_STRIP_TRAILING_WHITESPACE
250
+ COMMAND_ERROR_IS_FATAL ANY)
251
+
252
+ find_package(liburlparser CONFIG REQUIRED)
253
+ target_link_libraries(my_app PRIVATE urlparser::urlparser)
254
+ ```
255
+
256
+ For build systems that prefer plain paths over the target, `find_package` also sets:
257
+
258
+ | Variable | Value |
259
+ | ------------------------ | ------------------------------------------------------------------ |
260
+ | `urlparser_LIB_PATH` | full path of the compiled library (`liburlparser.a`, `urlparser.lib`, ...) |
261
+ | `urlparser_INCLUDE_PATH` | directory containing `urlparser.h` |
262
+
263
+ The same locations are available from the command line and from Python:
222
264
 
223
265
  ```sh
224
- # 1. Clone the repository with submodules (recursive)
225
- # --recursive is essential to download third-party libs like googletest
226
- git clone --recursive https://github.com/mohammadraziei/liburlparser
227
- cd liburlparser
266
+ python -m liburlparser --cmake-dir # directory with liburlparserConfig.cmake
267
+ python -m liburlparser --include-dir # directory with urlparser.h
268
+ python -m liburlparser --lib-dir # directory with the compiled library
269
+ ```
270
+
271
+ ```python
272
+ import liburlparser
273
+ liburlparser.get_cmake_dir(), liburlparser.get_include_dir(), liburlparser.get_lib_dir()
274
+ ```
228
275
 
229
- # 2. Configure the project
230
- # -B build tells CMake to create a 'build' directory and generate files there
231
- cmake -B build
276
+ A complete example project is in
277
+ [examples/find_liburlparser_via_python](examples/find_liburlparser_via_python).
232
278
 
233
- # 3. Build the project
234
- # --build abstracts the underlying build tool (Make, Ninja, MSBuild, etc.)
235
- cmake --build build --config Debug
279
+ #### 3. Build and install from source
236
280
 
237
- # 4. Run examples
238
- # Note: On Windows, the path might be ./build/Debug/example.exe
281
+ ```sh
282
+ git clone https://github.com/mohammadraziei/liburlparser
283
+ cd liburlparser
284
+
285
+ # configure and build (-B creates the 'build' directory)
286
+ cmake -B build -DCMAKE_BUILD_TYPE=Release
287
+ cmake --build build
288
+
289
+ # run the example (on Windows with multi-config generators: ./build/Release/example.exe)
239
290
  ./build/example
240
291
 
241
- # 5. Make install
242
- # --install handles the installation process
243
- sudo cmake --install build
292
+ # install the library, header and CMake package (add --prefix <dir> to choose where)
293
+ cmake --install build
294
+ ```
295
+
296
+ Then, in your project (add `-DCMAKE_PREFIX_PATH=<prefix>` if you used a custom prefix):
297
+
298
+ ```cmake
299
+ find_package(liburlparser CONFIG REQUIRED)
300
+ target_link_libraries(my_app PRIVATE urlparser::urlparser)
244
301
  ```
245
302
 
246
303
  ### Python and Command Line:
247
304
 
248
- Be aware that it required `python>=3.8`
305
+ Be aware that it requires `python>=3.10`
249
306
 
250
307
  #### Installation
251
308
 
252
309
  ###### from source
253
310
 
254
- To install from source, you must ensure all submodules are cloned:
255
-
256
311
  ```bash
257
- # 1. Clone recursively to get third-party dependencies
258
- git clone --recursive https://github.com/mohammadraziei/liburlparser
312
+ git clone https://github.com/mohammadraziei/liburlparser
259
313
  cd liburlparser
260
314
 
261
- # 2. Install using pip
262
315
  pip install .
263
316
 
264
317
  # Optional: If you want to see build logs
@@ -290,6 +343,18 @@ pip install ./liburlparser
290
343
 
291
344
  ### Performance
292
345
 
346
+ Up-to-date, reproducible results for both C++ and Python (compared against other libraries)
347
+ are on the **[Benchmarks page](https://mohammadraziei.github.io/liburlparser/benchmarks/)**.
348
+ The report is generated locally and published with the documentation:
349
+
350
+ ```sh
351
+ cmake -S benchmarks -B build-bench -DCMAKE_BUILD_TYPE=Release
352
+ cmake --build build-bench --target urlparser_benchmarks_report
353
+ # -> benchmarks/results/report.html
354
+ ```
355
+
356
+ The two tables below are the original measurements from March 2022.
357
+
293
358
  #### Extract From Host
294
359
 
295
360
  Tests were run on a file containing 10 million random domains from various top-level domains (Mar. 13rd 2022)
@@ -330,5 +395,6 @@ Project Link:
330
395
 
331
396
  - [https://github.com/mohammadraziei/liburlparser](https://github.com/mohammadraziei/liburlparser)
332
397
  - [https://pypi.org/project/liburlparser](https://pypi.org/project/liburlparser)
398
+ - [Documentation](https://mohammadraziei.github.io/liburlparser/) and [Benchmarks](https://mohammadraziei.github.io/liburlparser/benchmarks/)
333
399
 
334
400
  [license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=flat-square
@@ -0,0 +1,148 @@
1
+ cmake_minimum_required(VERSION 3.19)
2
+
3
+ # ==============================================================================
4
+ # liburlparser Benchmarks — fully standalone CMake project.
5
+ #
6
+ # This has NO relationship to the repository root — not even for liburlparser
7
+ # itself. Every language folder fetches liburlparser the exact same way it
8
+ # fetches any competitor: from https://github.com/mohammadraziei/liburlparser.git
9
+ # (C++, via FetchContent) or `pip install git+https://github.com/mohammadraziei/
10
+ # liburlparser.git` (Python). liburlparser is never a special case here — it's
11
+ # benchmarked exactly like ada or tldextract: one more entry in the same
12
+ # results table. (Mirrors the same structure as ctoon's own benchmarks/.)
13
+ #
14
+ # Build it on its own:
15
+ #
16
+ # cd benchmarks
17
+ # cmake -S . -B build-bench -DCMAKE_BUILD_TYPE=Release
18
+ # cmake --build build-bench --target urlparser_benchmarks
19
+ #
20
+ # Layout: one folder per language (cpp, python), each with its own
21
+ # CMakeLists.txt that fetches its own dependencies and defines an
22
+ # urlparser_benchmarks_<lang> target. A language is skipped with a warning
23
+ # only when its toolchain isn't found.
24
+ # ==============================================================================
25
+
26
+ project(UrlParserBenchmarks LANGUAGES CXX)
27
+
28
+ set(CMAKE_CXX_STANDARD 17)
29
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
30
+
31
+ if(NOT CMAKE_BUILD_TYPE)
32
+ set(CMAKE_BUILD_TYPE Release)
33
+ endif()
34
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
35
+ message(WARNING "Benchmarks are being built in Debug mode — numbers will "
36
+ "not reflect real performance. Pass -DCMAKE_BUILD_TYPE=Release.")
37
+ endif()
38
+
39
+ set(URLPARSER_BENCH_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
40
+ set(URLPARSER_BENCH_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
41
+ set(URLPARSER_GITHUB_URL "https://github.com/mohammadraziei/liburlparser.git")
42
+
43
+ # Two different "results" directories, two different lifetimes:
44
+ # - SCRATCH_DIR: each language's own raw JSON (cpp.json, python.json) -
45
+ # disposable build output, lives in the build dir, never committed.
46
+ # - RESULTS_DIR: the one artifact meant to survive - the standalone
47
+ # report.html that report/ renders from those JSONs - lives in the
48
+ # source tree so it can be committed and viewed on GitHub directly,
49
+ # with no build step required to see the last-generated numbers.
50
+ set(URLPARSER_BENCH_RESULTS_SCRATCH_DIR ${URLPARSER_BENCH_BINARY_DIR}/results)
51
+ file(MAKE_DIRECTORY ${URLPARSER_BENCH_RESULTS_SCRATCH_DIR})
52
+
53
+ set(URLPARSER_BENCH_RESULTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/results"
54
+ CACHE PATH "Where the final standalone report.html is written -- the one artifact meant to be committed")
55
+ file(MAKE_DIRECTORY ${URLPARSER_BENCH_RESULTS_DIR})
56
+
57
+ # ── Toolchain detection ─────────────────────────────────────────────────
58
+ # A language is skipped (with a warning) only when its toolchain itself
59
+ # isn't found. Everything else (venvs, pip installs, FetchContent) happens
60
+ # inside that language's own CMakeLists.txt once we know the toolchain
61
+ # exists. Needed here too, now, since corpus generation below runs Python.
62
+ find_package(Python3 COMPONENTS Interpreter)
63
+
64
+ # ── Corpus: fetch a real-world domain list, derive a URL list from it ─────
65
+ # 10,000 real, currently-registered domains (Majestic Million-derived),
66
+ # covering a wide range of TLDs/ccTLDs and subdomain shapes — not synthetic
67
+ # data generated just for this benchmark.
68
+ #
69
+ # Shared, single location for the downloaded/derived corpus - NOT per
70
+ # build directory (${URLPARSER_BENCH_BINARY_DIR} changes for every fresh
71
+ # `cmake -B <dir>`, which used to mean a fresh multi-hundred-KB download
72
+ # every time). Every build reuses this one copy; .gitignore'd, never
73
+ # committed. Standalone (non-CMake) tools under benchmarks/ read from here
74
+ # too - this is the single source of truth for the corpus, nothing
75
+ # downloads or derives it a second way anywhere else.
76
+ #
77
+ # The actual download + derivation logic lives in corpus/generate_corpus.py,
78
+ # not here: string/URL construction is a poor fit for CMake's DSL, and the
79
+ # derived urls.txt is round-tripped through ada_url's WHATWG-spec parser
80
+ # there (the same URL library this project's own benchmarks compare
81
+ # against) rather than trusted as hand-built strings.
82
+ set(URLPARSER_BENCH_CORPUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/corpus)
83
+ set(URLPARSER_BENCH_DOMAINS_FILE ${URLPARSER_BENCH_CORPUS_DIR}/domains.txt)
84
+ set(URLPARSER_BENCH_URLS_FILE ${URLPARSER_BENCH_CORPUS_DIR}/urls.txt)
85
+
86
+ if(Python3_Interpreter_FOUND AND (NOT EXISTS ${URLPARSER_BENCH_DOMAINS_FILE} OR NOT EXISTS ${URLPARSER_BENCH_URLS_FILE}))
87
+ # ada-url is a ~2MB prebuilt wheel with zero dependencies of its own -
88
+ # installed straight into the system/found Python3, no dedicated venv
89
+ # for it. (The separate, heavier venv in python/CMakeLists.txt -
90
+ # nanobind, scikit-build-core, tldextract, ... - is for actually
91
+ # *running* the Python benchmark later; unrelated to this one-off
92
+ # corpus-generation step and not worth sharing across the two.)
93
+ execute_process(COMMAND ${Python3_EXECUTABLE} -c "import ada_url" RESULT_VARIABLE _ada_url_present)
94
+ if(NOT _ada_url_present EQUAL 0)
95
+ execute_process(COMMAND ${Python3_EXECUTABLE} -m pip install -q --disable-pip-version-check --user ada-url
96
+ RESULT_VARIABLE _pip_rc)
97
+ if(NOT _pip_rc EQUAL 0)
98
+ # PEP 668 ("externally-managed-environment") refuses a plain
99
+ # --user install on modern Debian/Ubuntu system Pythons -
100
+ # --break-system-packages is the documented escape hatch for
101
+ # exactly this: one small, dependency-free utility package,
102
+ # not a project dependency going into the system environment.
103
+ execute_process(
104
+ COMMAND ${Python3_EXECUTABLE} -m pip install -q --disable-pip-version-check --user
105
+ --break-system-packages ada-url
106
+ RESULT_VARIABLE _pip_rc)
107
+ endif()
108
+ if(NOT _pip_rc EQUAL 0)
109
+ message(FATAL_ERROR "Failed to install ada-url (needed by benchmarks/corpus/generate_corpus.py)")
110
+ endif()
111
+ endif()
112
+
113
+ execute_process(
114
+ COMMAND ${Python3_EXECUTABLE} ${URLPARSER_BENCH_CORPUS_DIR}/generate_corpus.py
115
+ RESULT_VARIABLE _corpus_rc
116
+ )
117
+ if(NOT _corpus_rc EQUAL 0)
118
+ message(FATAL_ERROR "Failed to generate benchmark corpus")
119
+ endif()
120
+ elseif(NOT Python3_Interpreter_FOUND AND (NOT EXISTS ${URLPARSER_BENCH_DOMAINS_FILE} OR NOT EXISTS ${URLPARSER_BENCH_URLS_FILE}))
121
+ message(FATAL_ERROR "Python3 is required to generate the benchmark corpus (benchmarks/corpus/generate_corpus.py)")
122
+ endif()
123
+
124
+ file(STRINGS ${URLPARSER_BENCH_DOMAINS_FILE} URLPARSER_BENCH_DOMAINS)
125
+ list(LENGTH URLPARSER_BENCH_DOMAINS URLPARSER_BENCH_DOMAIN_COUNT)
126
+ message(STATUS "liburlparser benchmarks: domain corpus has ${URLPARSER_BENCH_DOMAIN_COUNT} domains")
127
+
128
+ add_custom_target(urlparser_benchmarks
129
+ COMMENT "Running all available liburlparser language benchmarks"
130
+ )
131
+
132
+
133
+ # C++ always runs: this project itself requires a CXX compiler to configure
134
+ # at all, so there's nothing to conditionally detect.
135
+ add_subdirectory(cpp)
136
+
137
+ if(Python3_Interpreter_FOUND)
138
+ add_subdirectory(python)
139
+
140
+ # The report needs at least the Python venv (for jinja2) to render -
141
+ # C++ is not a hard requirement for report generation itself, but this
142
+ # project always has a CXX compiler available (see above), so in
143
+ # practice both results are always present in the report.
144
+ add_subdirectory(report)
145
+ add_dependencies(urlparser_benchmarks urlparser_benchmarks_report)
146
+ else()
147
+ message(WARNING "Python3 not found — Python benchmark and HTML report skipped.")
148
+ endif()