diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 4338cdeba..d329f91d6 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -49,7 +49,7 @@ jobs: run: | git clone https://github.com/bitwuzla/bitwuzla.git cd bitwuzla - git checkout -b 0.2.0 0.2.0 + git checkout -b 0.4.0 0.4.0 python ./configure.py --shared cd build sudo ninja install diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6714e52e8..5a18131a3 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -51,7 +51,7 @@ jobs: run: | git clone https://github.com/bitwuzla/bitwuzla.git cd bitwuzla - git checkout -b 0.2.0 0.2.0 + git checkout -b 0.4.0 0.4.0 python ./configure.py --shared cd build sudo ninja install diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 276315bb4..9279ada15 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -54,7 +54,7 @@ jobs: run: | git clone https://github.com/bitwuzla/bitwuzla.git cd bitwuzla - git checkout -b 0.2.0 0.2.0 + git checkout -b 0.4.0 0.4.0 python ./configure.py --shared --prefix $(pwd)/install cd build sudo ninja install diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 36d336cd0..f98126b2f 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -194,7 +194,7 @@ jobs: run: | git clone https://github.com/bitwuzla/bitwuzla.git cd bitwuzla - git checkout -b 0.2.0 0.2.0 + git checkout -b 0.4.0 0.4.0 python ./configure.py --shared --prefix $(pwd)/install cd build sudo ninja install diff --git a/Dockerfile b/Dockerfile index 724a6d719..db119f18b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,11 +15,11 @@ RUN cd /tmp && \ tar xvf cap.tgz && cd capstone-4.0.2/ && ./make.sh && make install && rm -rf /tmp/cap* \ && ln -s /usr/lib/libcapstone.so.4 /usr/lib/x86_64-linux-gnu/libcapstone.so -# libbitwuzla >= 0.2.0 +# libbitwuzla >= 0.4.0 RUN cd /tmp && \ git clone https://github.com/bitwuzla/bitwuzla.git && \ cd bitwuzla && \ - git checkout -b 0.2.0 0.2.0 && \ + git checkout -b 0.4.0 0.4.0 && \ python3 ./configure.py --shared && \ cd build && \ ninja install && \ diff --git a/README.md b/README.md index 15cc85643..26d4c669c 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Triton relies on the following dependencies: * libboost (optional) >= 1.68 * libpython (optional) >= 3.6 * libz3 (optional) >= 4.6.0 https://github.com/Z3Prover/z3 -* libbitwuzla (optional) >= 0.2.x https://github.com/bitwuzla/bitwuzla +* libbitwuzla (optional) >= 0.4.x https://github.com/bitwuzla/bitwuzla * llvm (optional) >= 12 ``` diff --git a/src/libtriton/ast/bitwuzla/tritonToBitwuzla.cpp b/src/libtriton/ast/bitwuzla/tritonToBitwuzla.cpp index 096196475..e1af0a3c3 100644 --- a/src/libtriton/ast/bitwuzla/tritonToBitwuzla.cpp +++ b/src/libtriton/ast/bitwuzla/tritonToBitwuzla.cpp @@ -61,27 +61,28 @@ namespace triton { children.emplace_back(this->translatedNodes.at(n)); } + BitwuzlaTermManager* tm = bitwuzla_get_term_mgr(bzla); switch (node->getType()) { case ARRAY_NODE: { auto size = triton::ast::getInteger(node->getChildren()[0]); - auto isort = bitwuzla_mk_bv_sort(size); // index sort - auto vsort = bitwuzla_mk_bv_sort(8); // value sort - auto asort = bitwuzla_mk_array_sort(isort, vsort); // array sort - auto value = bitwuzla_mk_bv_value_uint64(vsort, 0); // const value - return bitwuzla_mk_const_array(asort, value); + auto isort = bitwuzla_mk_bv_sort(tm, size); // index sort + auto vsort = bitwuzla_mk_bv_sort(tm, 8); // value sort + auto asort = bitwuzla_mk_array_sort(tm, isort, vsort); // array sort + auto value = bitwuzla_mk_bv_value_uint64(tm, vsort, 0); // const value + return bitwuzla_mk_const_array(tm, asort, value); } case BSWAP_NODE: { auto bvsize = node->getBitvectorSize(); - auto bvsort = bitwuzla_mk_bv_sort(bvsize); - auto retval = bitwuzla_mk_term2(BITWUZLA_KIND_BV_AND, children[0], bitwuzla_mk_bv_value_uint64(bvsort, 0xff)); + auto bvsort = bitwuzla_mk_bv_sort(tm, bvsize); + auto retval = bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_AND, children[0], bitwuzla_mk_bv_value_uint64(tm, bvsort, 0xff)); for (triton::uint32 index = 8 ; index != bvsize ; index += triton::bitsize::byte) { - retval = bitwuzla_mk_term2(BITWUZLA_KIND_BV_SHL, retval, bitwuzla_mk_bv_value_uint64(bvsort, 8)); - retval = bitwuzla_mk_term2(BITWUZLA_KIND_BV_OR, retval, - bitwuzla_mk_term2(BITWUZLA_KIND_BV_AND, - bitwuzla_mk_term2(BITWUZLA_KIND_BV_SHR, children[0], bitwuzla_mk_bv_value_uint64(bvsort, index)), - bitwuzla_mk_bv_value_uint64(bvsort, 0xff) + retval = bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SHL, retval, bitwuzla_mk_bv_value_uint64(tm, bvsort, 8)); + retval = bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_OR, retval, + bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_AND, + bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SHR, children[0], bitwuzla_mk_bv_value_uint64(tm, bvsort, index)), + bitwuzla_mk_bv_value_uint64(tm, bvsort, 0xff) ) ); } @@ -89,146 +90,146 @@ namespace triton { } case BVADD_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_ADD, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_ADD, children[0], children[1]); case BVAND_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_AND, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_AND, children[0], children[1]); case BVASHR_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_ASHR, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_ASHR, children[0], children[1]); case BVLSHR_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SHR, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SHR, children[0], children[1]); case BVMUL_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_MUL, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_MUL, children[0], children[1]); case BVNAND_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_NAND, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_NAND, children[0], children[1]); case BVNEG_NODE: - return bitwuzla_mk_term1(BITWUZLA_KIND_BV_NEG, children[0]); + return bitwuzla_mk_term1(tm, BITWUZLA_KIND_BV_NEG, children[0]); case BVNOR_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_NOR, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_NOR, children[0], children[1]); case BVNOT_NODE: - return bitwuzla_mk_term1(BITWUZLA_KIND_BV_NOT, children[0]); + return bitwuzla_mk_term1(tm, BITWUZLA_KIND_BV_NOT, children[0]); case BVOR_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_OR, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_OR, children[0], children[1]); case BVROL_NODE: { auto childNodes = node->getChildren(); auto idx = triton::ast::getInteger(childNodes[1]); - return bitwuzla_mk_term1_indexed1(BITWUZLA_KIND_BV_ROLI, children[0], idx); + return bitwuzla_mk_term1_indexed1(tm, BITWUZLA_KIND_BV_ROLI, children[0], idx); } case BVROR_NODE: { auto childNodes = node->getChildren(); auto idx = triton::ast::getInteger(childNodes[1]); - return bitwuzla_mk_term1_indexed1(BITWUZLA_KIND_BV_RORI, children[0], idx); + return bitwuzla_mk_term1_indexed1(tm, BITWUZLA_KIND_BV_RORI, children[0], idx); } case BVSDIV_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SDIV, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SDIV, children[0], children[1]); case BVSGE_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SGE, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SGE, children[0], children[1]); case BVSGT_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SGT, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SGT, children[0], children[1]); case BVSHL_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SHL, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SHL, children[0], children[1]); case BVSLE_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SLE, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SLE, children[0], children[1]); case BVSLT_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SLT, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SLT, children[0], children[1]); case BVSMOD_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SMOD, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SMOD, children[0], children[1]); case BVSREM_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SREM, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SREM, children[0], children[1]); case BVSUB_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_SUB, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_SUB, children[0], children[1]); case BVUDIV_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_UDIV, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_UDIV, children[0], children[1]); case BVUGE_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_UGE, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_UGE, children[0], children[1]); case BVUGT_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_UGT, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_UGT, children[0], children[1]); case BVULE_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_ULE, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_ULE, children[0], children[1]); case BVULT_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_ULT, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_ULT, children[0], children[1]); case BVUREM_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_UREM, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_UREM, children[0], children[1]); case BVXNOR_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_XNOR, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_XNOR, children[0], children[1]); case BVXOR_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_BV_XOR, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_BV_XOR, children[0], children[1]); case BV_NODE: { auto childNodes = node->getChildren(); auto bv_size = triton::ast::getInteger(childNodes[1]); auto sort = this->bvSorts.find(bv_size); if (sort == this->bvSorts.end()) { - sort = this->bvSorts.insert({bv_size, bitwuzla_mk_bv_sort(bv_size)}).first; + sort = this->bvSorts.insert({bv_size, bitwuzla_mk_bv_sort(tm, bv_size)}).first; } // Handle bitvector value as integer if it small enough. if (bv_size <= sizeof(uint64_t) * 8) { auto bv_value = triton::ast::getInteger(childNodes[0]); - return bitwuzla_mk_bv_value_uint64(sort->second, bv_value); + return bitwuzla_mk_bv_value_uint64(tm, sort->second, bv_value); } auto bv_value = triton::ast::getInteger(childNodes[0]); - return bitwuzla_mk_bv_value(sort->second, bv_value.c_str(), 10); + return bitwuzla_mk_bv_value(tm, sort->second, bv_value.c_str(), 10); } case CONCAT_NODE: - return bitwuzla_mk_term(BITWUZLA_KIND_BV_CONCAT, children.size(), children.data()); + return bitwuzla_mk_term(tm, BITWUZLA_KIND_BV_CONCAT, children.size(), children.data()); case DISTINCT_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_DISTINCT, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_DISTINCT, children[0], children[1]); case EQUAL_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_EQUAL, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_EQUAL, children[0], children[1]); case EXTRACT_NODE: { auto childNodes = node->getChildren(); auto high = triton::ast::getInteger(childNodes[0]); auto low = triton::ast::getInteger(childNodes[1]); - return bitwuzla_mk_term1_indexed2(BITWUZLA_KIND_BV_EXTRACT, children[2], high, low); + return bitwuzla_mk_term1_indexed2(tm, BITWUZLA_KIND_BV_EXTRACT, children[2], high, low); } case FORALL_NODE: throw triton::exceptions::AstLifting("TritonToBitwuzla::translate(): FORALL node can't be converted due to a Bitwuzla issue (see #1062)."); case IFF_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_IFF, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_IFF, children[0], children[1]); case INTEGER_NODE: return (BitwuzlaTerm) 0; case ITE_NODE: - return bitwuzla_mk_term3(BITWUZLA_KIND_ITE, children[0], children[1], children[2]); + return bitwuzla_mk_term3(tm, BITWUZLA_KIND_ITE, children[0], children[1], children[2]); case LAND_NODE: - return bitwuzla_mk_term(BITWUZLA_KIND_AND, children.size(), children.data()); + return bitwuzla_mk_term(tm, BITWUZLA_KIND_AND, children.size(), children.data()); case LET_NODE: { auto childNodes = node->getChildren(); @@ -237,13 +238,13 @@ namespace triton { } case LNOT_NODE: - return bitwuzla_mk_term1(BITWUZLA_KIND_NOT, children[0]); + return bitwuzla_mk_term1(tm, BITWUZLA_KIND_NOT, children[0]); case LOR_NODE: - return bitwuzla_mk_term(BITWUZLA_KIND_OR, children.size(), children.data()); + return bitwuzla_mk_term(tm, BITWUZLA_KIND_OR, children.size(), children.data()); case LXOR_NODE: - return bitwuzla_mk_term(BITWUZLA_KIND_XOR, children.size(), children.data()); + return bitwuzla_mk_term(tm, BITWUZLA_KIND_XOR, children.size(), children.data()); case REFERENCE_NODE: { auto ref = reinterpret_cast(node.get())->getSymbolicExpression()->getAst(); @@ -251,10 +252,10 @@ namespace triton { } case SELECT_NODE: - return bitwuzla_mk_term2(BITWUZLA_KIND_ARRAY_SELECT, children[0], children[1]); + return bitwuzla_mk_term2(tm, BITWUZLA_KIND_ARRAY_SELECT, children[0], children[1]); case STORE_NODE: - return bitwuzla_mk_term3(BITWUZLA_KIND_ARRAY_STORE, children[0], children[1], children[2]); + return bitwuzla_mk_term3(tm, BITWUZLA_KIND_ARRAY_STORE, children[0], children[1], children[2]); case STRING_NODE: { std::string value = reinterpret_cast(node.get())->getString(); @@ -269,7 +270,7 @@ namespace triton { case SX_NODE: { auto childNodes = node->getChildren(); auto ext = triton::ast::getInteger(childNodes[0]); - return bitwuzla_mk_term1_indexed1(BITWUZLA_KIND_BV_SIGN_EXTEND, children[1], ext); + return bitwuzla_mk_term1_indexed1(tm, BITWUZLA_KIND_BV_SIGN_EXTEND, children[1], ext); } case VARIABLE_NODE: { @@ -277,16 +278,16 @@ namespace triton { auto size = symVar->getSize(); auto sort = this->bvSorts.find(size); if (sort == this->bvSorts.end()) { - sort = this->bvSorts.insert({size, bitwuzla_mk_bv_sort(size)}).first; + sort = this->bvSorts.insert({size, bitwuzla_mk_bv_sort(tm, size)}).first; } // If the conversion is used to evaluate a node, we concretize symbolic variables. if (this->isEval) { triton::uint512 value = reinterpret_cast(node.get())->evaluate(); if (size <= sizeof(uint64_t) * 8) { - return bitwuzla_mk_bv_value_uint64(sort->second, static_cast(value)); + return bitwuzla_mk_bv_value_uint64(tm, sort->second, static_cast(value)); } - return bitwuzla_mk_bv_value(sort->second, triton::utils::toString(value).c_str(), 10); + return bitwuzla_mk_bv_value(tm, sort->second, triton::utils::toString(value).c_str(), 10); } auto n = (BitwuzlaTerm) 0; @@ -299,7 +300,7 @@ namespace triton { } if (n == 0) { - n = bitwuzla_mk_const(sort->second, symVar->getName().c_str()); + n = bitwuzla_mk_const(tm, sort->second, symVar->getName().c_str()); variables[n] = symVar; } @@ -309,7 +310,7 @@ namespace triton { case ZX_NODE: { auto childNodes = node->getChildren(); auto ext = triton::ast::getInteger(childNodes[0]); - return bitwuzla_mk_term1_indexed1(BITWUZLA_KIND_BV_ZERO_EXTEND,children[1], ext); + return bitwuzla_mk_term1_indexed1(tm, BITWUZLA_KIND_BV_ZERO_EXTEND,children[1], ext); } default: diff --git a/src/libtriton/engines/solver/bitwuzla/bitwuzlaSolver.cpp b/src/libtriton/engines/solver/bitwuzla/bitwuzlaSolver.cpp index d26fccf06..b8e5af288 100644 --- a/src/libtriton/engines/solver/bitwuzla/bitwuzlaSolver.cpp +++ b/src/libtriton/engines/solver/bitwuzla/bitwuzlaSolver.cpp @@ -101,7 +101,8 @@ namespace triton { // Create solver. auto bzlaOptions = bitwuzla_options_new(); bitwuzla_set_option(bzlaOptions, BITWUZLA_OPT_PRODUCE_MODELS, 1); - auto bzla = bitwuzla_new(bzlaOptions); + auto bzlaTermMgr = bitwuzla_term_manager_new(); + auto bzla = bitwuzla_new(bzlaTermMgr, bzlaOptions); // Convert Triton' AST to solver terms. auto bzlaAst = triton::ast::TritonToBitwuzla(); @@ -149,9 +150,9 @@ namespace triton { // Negate current model to escape duplication in the next solution. const auto& symvar_sort = bzlaAst.getBitvectorSorts().at(it.second->getSize()); - auto cur_val = bitwuzla_mk_bv_value(symvar_sort, svalue, 2); - auto n = bitwuzla_mk_term2(BITWUZLA_KIND_EQUAL, it.first, cur_val); - solution.push_back(bitwuzla_mk_term1(BITWUZLA_KIND_NOT, n)); + auto cur_val = bitwuzla_mk_bv_value(bzlaTermMgr, symvar_sort, svalue, 2); + auto n = bitwuzla_mk_term2(bzlaTermMgr, BITWUZLA_KIND_EQUAL, it.first, cur_val); + solution.push_back(bitwuzla_mk_term1(bzlaTermMgr, BITWUZLA_KIND_NOT, n)); } // Check that model is available. @@ -165,7 +166,7 @@ namespace triton { if (--limit) { // Escape last model. if (solution.size() > 1) { - bitwuzla_assert(bzla, bitwuzla_mk_term(BITWUZLA_KIND_OR, solution.size(), solution.data())); + bitwuzla_assert(bzla, bitwuzla_mk_term(bzlaTermMgr, BITWUZLA_KIND_OR, solution.size(), solution.data())); } else { bitwuzla_assert(bzla, solution.front()); @@ -183,6 +184,7 @@ namespace triton { *solvingTime = std::chrono::duration_cast(end - start).count(); bitwuzla_delete(bzla); + bitwuzla_term_manager_delete(bzlaTermMgr); bitwuzla_options_delete(bzlaOptions); return ret; @@ -214,7 +216,8 @@ namespace triton { auto bzlaOptions = bitwuzla_options_new(); bitwuzla_set_option(bzlaOptions, BITWUZLA_OPT_PRODUCE_MODELS, 1); - auto bzla = bitwuzla_new(bzlaOptions); + auto bzlaTermMgr = bitwuzla_term_manager_new(); + auto bzla = bitwuzla_new(bzlaTermMgr, bzlaOptions); // Query check-sat on empty solver to put Bitwuzla in SAT-state. Thus, it should be able to evaluate concrete formulas. if (bitwuzla_check_sat(bzla) != BITWUZLA_SAT) { @@ -235,6 +238,7 @@ namespace triton { } bitwuzla_delete(bzla); + bitwuzla_term_manager_delete(bzlaTermMgr); bitwuzla_options_delete(bzlaOptions); return res; diff --git a/src/scripts/docker/Dockerfile b/src/scripts/docker/Dockerfile index 7eff5f68f..6e027846f 100644 --- a/src/scripts/docker/Dockerfile +++ b/src/scripts/docker/Dockerfile @@ -40,7 +40,7 @@ RUN echo "[+] Download, build and install Bitwuzla" && \ cd $DEPENDENCIES_DIR && \ git clone https://github.com/bitwuzla/bitwuzla.git && \ cd bitwuzla && \ - git checkout -b 0.2.0 0.2.0 && \ + git checkout -b 0.4.0 0.4.0 && \ export PY310_PATH=$(dirname $(realpath -L $(which python3.10))) && \ CC=clang CXX=clang++ PATH=$PATH:$PY310_PATH python3.10 ./configure.py --shared --prefix $(pwd)/install && \ cd build && \