if(PIPY_STATIC) cmake_minimum_required(VERSION 3.13) else() cmake_minimum_required(VERSION 3.10) endif() project(pipy) option(PIPY_STATICLIB "Build Pipy as static library" OFF) option(PIPY_SHARED "Build Pipy as dynamic library" OFF) option(PIPY_GUI "include builtin GUI" OFF) option(PIPY_CODEBASES "include builtin codebases in the executable" OFF) option(PIPY_CUSTOM_CODEBASES "include custom codebases in the executable (/:,/:,...)" "") option(PIPY_DEFAULT_OPTIONS "fixed command line options to insert before user options" OFF) option(PIPY_BPF "enable eBPF support" ON) option(PIPY_SOIL_FREED_SPACE "invalidate freed space for debugging" OFF) option(PIPY_ASSERT_SAME_THREAD "enable assertions for strict inner-thread data access" OFF) option(PIPY_ZLIB "external zlib location" "") option(PIPY_OPENSSL "external libopenssl location" "") option(PIPY_BROTLI "external brotli location" "") option(PIPY_STATIC "statically link to libc" OFF) option(PIPY_LTO "enable LTO" OFF) option(PIPY_USE_NTLS, "Use externally compiled TongSuo Crypto library instead of OpenSSL. Used with PIPY_OPENSSL" OFF) option(PIPY_USE_SYSTEM_ZLIB "Use system installed zlib" OFF) option(PIPY_USE_SYSTEM_OPENSSL "Use system installed OpenSSL" OFF) option(PIPY_USE_OPENSSL1, "Use openssl v1 when compiling pipy" OFF) set(BUILD_SHARED_LIBS OFF) set(BUILD_TESTING OFF) if(MSVC) add_compile_options(/W0 $<$:/MT> $<$:/MTd> $<$:/MT> ) endif(MSVC) add_subdirectory(deps/yajl-2.1.0) add_subdirectory(deps/libyaml-0.2.5) option(BUILD_tools "build the xmlwf tool for expat library" OFF) option(BUILD_examples "build the examples for expat library" OFF) option(BUILD_tests "build the tests for expat library" OFF) option(BUILD_shared "build a shared expat library" OFF) option(BUILD_doc "build man page for xmlwf" OFF) add_subdirectory(deps/libexpat-R_2_2_6/expat) option(LEVELDB_BUILD_TESTS "Build LevelDB's unit tests" OFF) option(LEVELDB_BUILD_BENCHMARKS "Build LevelDB's benchmarks" OFF) option(LEVELDB_INSTALL "Install LevelDB's header and library" OFF) add_subdirectory(deps/leveldb-1.23) if(PIPY_SHARED AND UNIX AND NOT APPLE) # Ensure position-independent code for static leveldb set_target_properties(leveldb PROPERTIES POSITION_INDEPENDENT_CODE ON) endif() set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) # Default build type is Debug if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug") endif() # Ignore COMPILE_DEFINITIONS_ properties cmake_policy(SET CMP0043 NEW) # Link libraries by full path even in implicit directories. cmake_policy(SET CMP0060 NEW) # ``INTERPROCEDURAL_OPTIMIZATION`` is enforced when enabled. cmake_policy(SET CMP0069 NEW) # Use ccache if available find_program(CCACHE_PROGRAM ccache) mark_as_advanced(FORCE CCACHE_PROGRAM) if(CCACHE_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") endif() include(c++-standards) include(compiler-options) include(sanitizers) # Require C++ 11 cxx_11() # enable LTO/IPO for all targets. Doesn't work with GCC. if(PIPY_LTO AND(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")) message("Enabling LTO") include(link-time-optimization) link_time_optimization() else() message("LTO is disabled") endif() if(WIN32) set(LIB_Z zlib.lib) set(LIB_CRYPTO libcrypto.lib) set(LIB_SSL libssl.lib) set(LIB_BROTLI libbrotlidec-static.lib) set(EXT_SHELL cmd) else(WIN32) set(LIB_Z libz.a) set(LIB_CRYPTO libcrypto.a) set(LIB_SSL libssl.a) set(LIB_BROTLI libbrotlidec-static.a) set(EXT_SHELL sh) endif(WIN32) if(PIPY_ZLIB) set(ZLIB_INC_DIR ${PIPY_ZLIB}/include) set(ZLIB_LIB ${PIPY_ZLIB}/lib/${LIB_Z}) else() if(PIPY_USE_SYSTEM_ZLIB) SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") find_package(ZLIB REQUIRED) set(ZLIB_LIB -lz) else(PIPY_USE_SYSTEM_ZLIB) add_subdirectory(deps/zlib-1.3.1) set(ZLIB_INC_DIR "${CMAKE_SOURCE_DIR}/deps/zlib-1.3.1" "${CMAKE_BINARY_DIR}/deps/zlib-1.3.1") set(ZLIB_LIB zlibstatic) if(PIPY_SHARED AND UNIX AND NOT APPLE) # Ensure position-independent code for static zlib set_target_properties(zlibstatic PROPERTIES POSITION_INDEPENDENT_CODE ON) endif() endif(PIPY_USE_SYSTEM_ZLIB) endif() if(PIPY_USE_OPENSSL1) add_definitions(-DPIPY_USE_OPENSSL1) endif() if(PIPY_USE_SYSTEM_OPENSSL) find_package(OpenSSL REQUIRED) if(OPENSSL_FOUND) set(OPENSSL_INC_DIR ${OPENSSL_INCLUDE_DIR}) message(STATUS "Using system-installed OpenSSL") else() message(FATAL_ERROR "System OpenSSL not found. Set PIPY_USE_SYSTEM_OPENSSL to OFF or install OpenSSL.") endif() elseif(PIPY_OPENSSL) if(PIPY_USE_NTLS) add_definitions(-DPIPY_USE_NTLS) endif(PIPY_USE_NTLS) set(OPENSSL_INC_DIR ${PIPY_OPENSSL}/include) set(OPENSSL_LIB_DIR ${PIPY_OPENSSL}/lib) else() if (DEFINED PIPY_USE_OPENSSL1) message(FATAL_ERROR "Error: OpenSSL v1 detected (PIPY_USE_OPENSSL1 is set).\n" "To compile with OpenSSL v1, you must set one of the following options:\n" " - PIPY_OPENSSL: Provide a custom OpenSSL installation path.\n" " - PIPY_USE_SYSTEM_OPENSSL: Use the system-installed OpenSSL library.\n" "Please configure CMake with the correct option and try again." ) endif() set(OPENSSL_SRC_DIR ${CMAKE_SOURCE_DIR}/deps/openssl-3.2.0) set(OPENSSL_LIB_DIR ${OPENSSL_SRC_DIR}/build) set(OPENSSL_INC_DIR ${OPENSSL_SRC_DIR}/include ${OPENSSL_LIB_DIR}/include) file(MAKE_DIRECTORY "${OPENSSL_SRC_DIR}/build") if(WIN32) add_custom_command( OUTPUT ${OPENSSL_LIB_DIR}/${LIB_CRYPTO} ${OPENSSL_LIB_DIR}/${LIB_SSL} WORKING_DIRECTORY ${OPENSSL_SRC_DIR}/build COMMAND cmd ARGS /C set COMMAND perl ARGS ../Configure no-shared no-tests VC-WIN64A COMMAND nmake VERBATIM COMMENT "Building OpenSSL" ) else() add_custom_command( OUTPUT ${OPENSSL_LIB_DIR}/${LIB_CRYPTO} ${OPENSSL_LIB_DIR}/${LIB_SSL} WORKING_DIRECTORY ${OPENSSL_SRC_DIR} COMMAND mkdir -p ${OPENSSL_SRC_DIR}/build COMMAND cd ${OPENSSL_SRC_DIR}/build && CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} ../config no-shared no-tests && make -j2 VERBATIM COMMENT "Building OpenSSL" ) endif() endif() if(NOT PIPY_USE_SYSTEM_OPENSSL) add_custom_target(OpenSSL DEPENDS ${OPENSSL_LIB_DIR}/${LIB_CRYPTO} ${OPENSSL_LIB_DIR}/${LIB_SSL}) endif() if(PIPY_BROTLI) set(BROTLI_INC_DIR ${PIPY_BROTLI}/include) set(BROTLI_LIB ${PIPY_BROTLI}/lib/${LIB_BROTLI}) else() set(BROTLI_BUNDLED_MODE ON CACHE BOOL "" FORCE) set(BROTLI_DISABLE_TESTS ON CACHE BOOL "" FORCE) add_subdirectory(deps/brotli-1.0.9) set(BROTLI_INC_DIR "${CMAKE_SOURCE_DIR}/deps/brotli-1.0.9/c/include") set(BROTLI_LIB brotlidec-static) endif(PIPY_BROTLI) add_definitions( -DPIPY_HOST="${CMAKE_HOST_SYSTEM} ${CMAKE_HOST_SYSTEM_PROCESSOR}" -DXML_STATIC=1 ) if(WIN32) add_definitions( -D_WIN32_WINNT=0x0601 -D_USE_MATH_DEFINES ) else() add_definitions(-D_GNU_SOURCE) endif() if(NOT MSVC) add_compile_options( -Wall -Wno-overloaded-virtual -Wno-delete-non-virtual-dtor -Wno-sign-compare -Wno-deprecated-declarations ) endif() include_directories( "${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/include" "${CMAKE_SOURCE_DIR}/deps/asio-1.28.0/include" "${CMAKE_BINARY_DIR}/deps" "${CMAKE_BINARY_DIR}/deps/yajl-2.1.0/yajl-2.1.0/include" "${CMAKE_BINARY_DIR}/deps/libyaml-0.2.5/include" "${CMAKE_BINARY_DIR}/deps/libexpat-R_2_2_6/expat/lib" "${CMAKE_SOURCE_DIR}/deps/libexpat-R_2_2_6/expat/lib" "${CMAKE_SOURCE_DIR}/deps/leveldb-1.23/include" "${CMAKE_SOURCE_DIR}/deps/sqlite-3.43.2" "${OPENSSL_INC_DIR}" "${BROTLI_INC_DIR}" ) if(NOT PIPY_USE_SYSTEM_ZLIB) include_directories("${ZLIB_INC_DIR}") endif() add_subdirectory(test/benchmark/baseline) SET(PIPY_SRC src/admin-link.cpp src/admin-proxy.cpp src/admin-service.cpp src/api/algo.cpp src/api/bgp.cpp src/api/bpf.cpp src/api/configuration.cpp src/api/console.cpp src/api/crypto.cpp src/api/c-string.cpp src/api/c-struct.cpp src/api/dns.cpp src/api/hessian.cpp src/api/http.cpp src/api/ip.cpp src/api/json.cpp src/api/logging.cpp src/api/os.cpp src/api/pipeline-api.cpp src/api/pipy.cpp src/api/print.cpp src/api/protobuf.cpp src/api/resp.cpp src/api/stats.cpp src/api/sqlite.cpp src/api/swap.cpp src/api/thrift.cpp src/api/timeout.cpp src/api/url.cpp src/api/xml.cpp src/api/yaml.cpp src/api/zlib.cpp src/buffer.cpp src/codebase.cpp src/codebase-store.cpp src/compressor.cpp src/context.cpp src/data.cpp src/deframer.cpp src/elf.cpp src/event.cpp src/event-queue.cpp src/fetch.cpp src/file.cpp src/filter.cpp src/filters/bgp.cpp src/filters/branch.cpp src/filters/chain.cpp src/filters/compress.cpp src/filters/connect.cpp src/filters/decompress.cpp src/filters/deframe.cpp src/filters/demux.cpp src/filters/deposit-message.cpp src/filters/detect-protocol.cpp src/filters/dubbo.cpp src/filters/dummy.cpp src/filters/dump.cpp src/filters/exec.cpp src/filters/fcgi.cpp src/filters/fork.cpp src/filters/handle.cpp src/filters/http.cpp src/filters/http2.cpp src/filters/insert.cpp src/filters/link.cpp src/filters/link-async.cpp src/filters/loop.cpp src/filters/mime.cpp src/filters/mqtt.cpp src/filters/mux.cpp src/filters/netlink.cpp src/filters/on-body.cpp src/filters/on-event.cpp src/filters/on-message.cpp src/filters/on-start.cpp src/filters/pack.cpp src/filters/pipe.cpp src/filters/print.cpp src/filters/produce.cpp src/filters/proxy-protocol.cpp src/filters/read.cpp src/filters/repeat.cpp src/filters/replace.cpp src/filters/replace-body.cpp src/filters/replace-event.cpp src/filters/replace-message.cpp src/filters/replace-start.cpp src/filters/replay.cpp src/filters/resp.cpp src/filters/socks.cpp src/filters/split.cpp src/filters/swap.cpp src/filters/tee.cpp src/filters/thrift.cpp src/filters/throttle.cpp src/filters/tls.cpp src/filters/use.cpp src/filters/wait.cpp src/filters/websocket.cpp src/fs.cpp src/fstream.cpp src/graph.cpp src/gui-tarball.cpp src/inbound.cpp src/input.cpp src/kmp.cpp src/listener.cpp src/log.cpp src/main.cpp src/main-options.cpp src/message.cpp src/module.cpp src/net.cpp src/nmi.cpp src/options.cpp src/os-platform.cpp src/outbound.cpp src/pipeline.cpp src/pipeline-lb.cpp src/pjs/builtin.cpp src/pjs/expr.cpp src/pjs/module.cpp src/pjs/parser.cpp src/pjs/stmt.cpp src/pjs/tree.cpp src/pjs/types.cpp src/signal.cpp src/socket.cpp src/status.cpp src/store.cpp src/str-map.cpp src/table.cpp src/tar.cpp src/task.cpp src/thread.cpp src/timer.cpp src/utils.cpp src/watch.cpp src/worker.cpp src/worker-thread.cpp deps/sqlite-3.43.2/sqlite3.c ) if(IOS) add_definitions(-D__APPLE__ -DTARGET_OS_IOS) endif(IOS) if(PIPY_SHARED) add_definitions(-DPIPY_SHARED) add_library(pipy SHARED ${PIPY_SRC}) elseif(PIPY_STATICLIB) add_definitions(-DPIPY_SHARED) add_library(pipy STATIC ${PIPY_SRC}) else() add_executable(pipy ${PIPY_SRC}) endif() execute_process( COMMAND ${CMAKE_SOURCE_DIR}/generate_version_h.${EXT_SHELL} ${CMAKE_BINARY_DIR}/deps/version.h WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) add_custom_target(GenVer DEPENDS ${CMAKE_BINARY_DIR}/deps/version.h) add_dependencies(pipy yajl_s expat ${BROTLI_LIB} GenVer) if(NOT PIPY_USE_SYSTEM_OPENSSL) add_dependencies(pipy OpenSSL) endif() if(NOT PIPY_USE_SYSTEM_ZLIB) add_dependencies(pipy ${ZLIB_LIB}) endif() find_program(NODEJS_EXECUTABLE NAMES node nodejs HINTS $ENV{NODE_DIR} PATH_SUFFIXES bin $ENV{HOMEBREW_PREFIX} DOC "Node.js interpreter") if(NODEJS_EXECUTABLE) message("NodeJS found at: ${NODEJS_EXECUTABLE}") endif() if(PIPY_GUI) add_definitions(-DPIPY_USE_GUI) if(NOT NODEJS_EXECUTABLE) message(FATAL_ERROR "Nodejs installation not found.") endif() add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/deps/gui.tar.h COMMAND ${NODEJS_EXECUTABLE} ARGS pack-gui.js ${CMAKE_BINARY_DIR}/deps/gui.tar.h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/gui DEPENDS gui/pack-gui.js ${CMAKE_SOURCE_DIR}/public/index.html ) add_custom_target(PackGui DEPENDS ${CMAKE_BINARY_DIR}/deps/gui.tar.h) add_dependencies(pipy PackGui) endif() if(PIPY_CODEBASES) add_definitions(-DPIPY_USE_CODEBASES) if(NOT NODEJS_EXECUTABLE) message(FATAL_ERROR "Nodejs installation not found.") endif() add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/deps/codebases.tar.gz.h COMMAND ${NODEJS_EXECUTABLE} ARGS pack-codebases.js ${CMAKE_BINARY_DIR}/deps/codebases.tar.gz.h ${PIPY_CUSTOM_CODEBASES} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/gui DEPENDS gui/pack-codebases.js ${CMAKE_SOURCE_DIR}/tutorial ${CMAKE_SOURCE_DIR}/samples ) add_custom_target(PackCodebases DEPENDS ${CMAKE_BINARY_DIR}/deps/codebases.tar.gz.h) add_dependencies(pipy PackCodebases) endif() if(PIPY_DEFAULT_OPTIONS) add_definitions(-DPIPY_DEFAULT_OPTIONS="${PIPY_DEFAULT_OPTIONS}") endif() if(PIPY_BPF) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_SYSTEM_VERSION VERSION_GREATER_EQUAL 4.18) add_definitions(-DPIPY_USE_BPF) message("eBPF is enabled") endif() endif() endif() if(PIPY_SOIL_FREED_SPACE) add_definitions(-DPIPY_SOIL_FREED_SPACE) endif() if(PIPY_ASSERT_SAME_THREAD) add_definitions(-DPIPY_ASSERT_SAME_THREAD) endif() if(PIPY_RFC8998) add_definitions(-DPIPY_USE_RFC8998) endif(PIPY_RFC8998) if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "-Wl,-exported_symbols_list ${CMAKE_SOURCE_DIR}/include/pipy/nmi-exports.lst") elseif(WIN32) set(CMAKE_EXE_LINKER_FLAGS "/DEF:${CMAKE_SOURCE_DIR}/include/pipy/nmi-exports.def") else() set(CMAKE_EXE_LINKER_FLAGS "-Wl,--dynamic-list ${CMAKE_SOURCE_DIR}/include/pipy/nmi-exports.txt") endif() if(PIPY_STATIC) target_link_options(pipy PRIVATE -static) endif() target_link_libraries( pipy yajl_s yaml expat ${ZLIB_LIB} ${BROTLI_LIB} leveldb ) if(PIPY_USE_SYSTEM_OPENSSL) target_link_libraries(pipy ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) else() target_link_libraries(pipy ${OPENSSL_LIB_DIR}/${LIB_SSL} ${OPENSSL_LIB_DIR}/${LIB_CRYPTO}) endif() if(WIN32) target_link_libraries(pipy crypt32 userenv) elseif(ANDROID) target_link_libraries(pipy -pthread -ldl) else() target_link_libraries(pipy -pthread -ldl -lutil) endif()