@@ -26,31 +26,70 @@ set(CPPVERIFY_Z3_SOURCE_DIR "" CACHE PATH "Path to a Z3 source tree (overrides t
2626get_filename_component (CPPVERIFY_REPO_ROOT
2727 "${CMAKE_CURRENT_LIST_DIR } /../../.." ABSOLUTE )
2828
29- function (cppverify_z3_apply_build_options )
30- set (Z3_BUILD_LIBZ3_SHARED OFF CACHE BOOL "" FORCE )
31- set (Z3_BUILD_EXECUTABLE OFF CACHE BOOL "" FORCE )
32- set (Z3_BUILD_TEST_EXECUTABLES OFF CACHE BOOL "" FORCE )
33- endfunction ()
34-
35- function (cppverify_z3_register_alias )
36- if (TARGET libz3)
37- if (NOT TARGET cppverify_z3)
38- add_library (cppverify_z3 ALIAS libz3 )
39- endif ()
40- elseif (TARGET z3)
41- if (NOT TARGET cppverify_z3)
42- add_library (cppverify_z3 ALIAS z3 )
43- endif ()
29+ # Build vendored Z3 as an isolated ExternalProject rather than add_subdirectory.
30+ #
31+ # Why ExternalProject and not add_subdirectory: Z3's CMake declares a library
32+ # component target literally named `opt` (z3_add_component(opt ...)). LLVM's
33+ # monorepo also declares an `opt` executable (llvm/tools/opt). Pulling Z3 into
34+ # the same CMake project via add_subdirectory/FetchContent makes both `opt`
35+ # targets live in one namespace and configure fails with CMP0002 (duplicate
36+ # target). ExternalProject runs Z3's CMake in a separate build, so its targets
37+ # never collide with LLVM's. We then consume the installed static lib through an
38+ # IMPORTED target.
39+ #
40+ # Sources for the build (either an on-disk tree or a git clone) are handled by
41+ # the SOURCE_DIR / GIT_REPOSITORY arguments threaded in by the callers.
42+ function (cppverify_z3_build_external )
43+ cmake_parse_arguments (Z3EP "" "SOURCE_DIR;GIT_REPOSITORY;GIT_TAG" "" ${ARGN} )
44+ include (ExternalProject )
45+
46+ set (_prefix "${CMAKE_BINARY_DIR } /cppverify-z3" )
47+ set (_install "${_prefix} /install" )
48+ set (_incdir "${_install} /include" )
49+ set (_libpath "${_install} /lib/${CMAKE_STATIC_LIBRARY_PREFIX } z3${CMAKE_STATIC_LIBRARY_SUFFIX } " )
50+
51+ if (Z3EP_SOURCE_DIR )
52+ set (_src_args SOURCE_DIR "${Z3EP_SOURCE_DIR } " )
53+ message (STATUS "CppVerify: building vendored Z3 (ExternalProject) from ${Z3EP_SOURCE_DIR } " )
4454 else ()
45- message (FATAL_ERROR "Z3 build did not produce libz3 or z3 CMake target" )
55+ set (_src_args
56+ GIT_REPOSITORY "${Z3EP_GIT_REPOSITORY} "
57+ GIT_TAG "${Z3EP_GIT_TAG} "
58+ GIT_SHALLOW TRUE )
59+ message (STATUS "CppVerify: building vendored Z3 (ExternalProject) ${Z3EP_GIT_TAG} "
60+ "(first build needs network)" )
4661 endif ()
47- endfunction ()
4862
49- function (cppverify_z3_from_subdirectory z3_src binary_dir )
50- cppverify_z3_apply_build_options ()
51- message (STATUS "CppVerify: building vendored Z3 from ${z3_src} " )
52- add_subdirectory ("${z3_src} " "${binary_dir} " EXCLUDE_FROM_ALL )
53- cppverify_z3_register_alias ()
63+ ExternalProject_Add (cppverify_z3_ep
64+ ${_src_args}
65+ PREFIX "${_prefix} "
66+ CMAKE_CACHE_ARGS
67+ -DCMAKE_BUILD_TYPE:STRING=Release
68+ -DCMAKE_INSTALL_PREFIX:PATH=${_install}
69+ -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
70+ -DZ3_BUILD_LIBZ3_SHARED:BOOL=OFF
71+ -DZ3_BUILD_EXECUTABLE:BOOL=OFF
72+ -DZ3_BUILD_TEST_EXECUTABLES:BOOL=OFF
73+ -DZ3_BUILD_DOCUMENTATION:BOOL=OFF
74+ -DZ3_ENABLE_EXAMPLE_TARGETS:BOOL=OFF
75+ BUILD_BYPRODUCTS "${_libpath} "
76+ USES_TERMINAL_DOWNLOAD TRUE
77+ USES_TERMINAL_BUILD TRUE )
78+
79+ # INTERFACE_INCLUDE_DIRECTORIES must exist at configure time.
80+ file (MAKE_DIRECTORY "${_incdir} " )
81+
82+ find_package (Threads REQUIRED )
83+ add_library (cppverify_z3 STATIC IMPORTED GLOBAL )
84+ set_target_properties (cppverify_z3 PROPERTIES
85+ IMPORTED_LOCATION "${_libpath} "
86+ INTERFACE_INCLUDE_DIRECTORIES "${_incdir} "
87+ INTERFACE_LINK_LIBRARIES "Threads::Threads;${CMAKE_DL_LIBS } " )
88+
89+ # Ensure the ExternalProject is built before anything links the imported lib.
90+ # BUILD_BYPRODUCTS handles Ninja ordering; this property lets consuming targets
91+ # add an explicit dependency for the Makefiles generator too.
92+ set_property (GLOBAL PROPERTY CPPVERIFY_Z3_EP_TARGET cppverify_z3_ep)
5493endfunction ()
5594
5695function (cppverify_z3_try_system out_var )
@@ -101,22 +140,14 @@ function(cppverify_z3_try_local out_var)
101140 set (${out_var} "" PARENT_SCOPE )
102141 return ()
103142 endif ()
104- cppverify_z3_from_subdirectory ( "${_src} " " ${ CMAKE_BINARY_DIR } /cppverify-z3-build " )
143+ cppverify_z3_build_external ( SOURCE_DIR "${_src} " )
105144 set (${out_var} cppverify_z3 PARENT_SCOPE )
106145endfunction ()
107146
108147function (cppverify_z3_try_fetch out_var )
109- include (FetchContent )
110- cppverify_z3_apply_build_options ()
111- message (STATUS "CppVerify: fetching Z3 ${CPPVERIFY_Z3_GIT_TAG} (first build needs network)" )
112- FetchContent_Declare (
113- cppverify_z3_src
148+ cppverify_z3_build_external (
114149 GIT_REPOSITORY https://github.com/Z3Prover/z3.git
115- GIT_TAG ${CPPVERIFY_Z3_GIT_TAG}
116- GIT_SHALLOW TRUE
117- )
118- FetchContent_MakeAvailable (cppverify_z3_src)
119- cppverify_z3_register_alias ()
150+ GIT_TAG ${CPPVERIFY_Z3_GIT_TAG} )
120151 set (${out_var} cppverify_z3 PARENT_SCOPE )
121152endfunction ()
122153
0 commit comments