osquery-1/CMake/CMakeLibs.cmake
2017-10-09 00:27:28 -07:00

423 lines
15 KiB
CMake

# Copyright (c) 2014-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
# osquery-specific helper macros
macro(LOG_PLATFORM NAME)
set(LINK "http://osquery.readthedocs.io/en/stable/development/building/")
LOG("Welcome to osquery's build-- thank you for your patience! :)")
LOG("For a brief tutorial see: ${ESC}[1m${LINK}${ESC}[m")
if(NOT WINDOWS)
LOG("If at first you dont succeed, perhaps: make distclean; make depsclean")
endif()
LOG("Building for platform ${ESC}[36;1m${NAME} (${OSQUERY_BUILD_PLATFORM}, ${OSQUERY_BUILD_DISTRO})${ESC}[m")
LOG("Building osquery version ${ESC}[36;1m ${OSQUERY_BUILD_VERSION} sdk ${OSQUERY_BUILD_SDK_VERSION}${ESC}[m")
endmacro(LOG_PLATFORM)
macro(LOG_LIBRARY NAME PATH)
set(CACHE_NAME "LOG_LIBRARY_${NAME}")
if(NOT DEFINED ${CACHE_NAME} OR NOT ${${CACHE_NAME}})
set(${CACHE_NAME} TRUE CACHE BOOL "Write log line for ${NAME} library.")
set(BUILD_POSITION -1)
string(FIND "${PATH}" "${CMAKE_BINARY_DIR}" BUILD_POSITION)
string(FIND "${PATH}" "NOTFOUND" NOTFOUND_POSITION)
if(${NOTFOUND_POSITION} GREATER 0)
WARNING_LOG("Could not find library: ${NAME}")
else()
if(${BUILD_POSITION} EQUAL 0)
string(LENGTH "${CMAKE_BINARY_DIR}" BUILD_DIR_LENGTH)
string(SUBSTRING "${PATH}" ${BUILD_DIR_LENGTH} -1 LIB_PATH)
LOG("Found osquery-built library ${ESC}[32m${LIB_PATH}${ESC}[m")
else()
LOG("Found library ${ESC}[32m${PATH}${ESC}[m")
endif()
endif()
endif()
endmacro(LOG_LIBRARY)
macro(SET_OSQUERY_COMPILE TARGET)
set(OPTIONAL_FLAGS ${ARGN})
list(LENGTH OPTIONAL_FLAGS NUM_OPTIONAL_FLAGS)
if(${NUM_OPTIONAL_FLAGS} GREATER 0)
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "${OPTIONAL_FLAGS}")
endif()
if(DO_CLANG_TIDY AND NOT "${TARGET}" STREQUAL "osquery_extensions")
set_target_properties(${TARGET} PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif()
endmacro(SET_OSQUERY_COMPILE)
macro(ADD_DEFAULT_LINKS TARGET ADDITIONAL)
if(DEFINED ENV{OSQUERY_BUILD_SHARED})
target_link_libraries(${TARGET} libosquery_shared)
if(${ADDITIONAL})
target_link_libraries(${TARGET} libosquery_additional_shared)
endif()
target_link_libraries(${TARGET} "-Wl,-rpath,${CMAKE_BINARY_DIR}/osquery")
target_link_libraries(${TARGET} ${OSQUERY_LINKS})
if(${ADDITIONAL})
target_link_libraries(${TARGET} ${OSQUERY_ADDITIONAL_LINKS})
endif()
else()
TARGET_OSQUERY_LINK_WHOLE(${TARGET} libosquery)
if(${ADDITIONAL})
TARGET_OSQUERY_LINK_WHOLE(${TARGET} libosquery_additional)
endif()
endif()
endmacro()
macro(ADD_OSQUERY_PYTHON_TEST TEST_NAME SOURCE)
if(NOT DEFINED ENV{SKIP_INTEGRATION_TESTS})
add_test(NAME python_${TEST_NAME}
COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_SOURCE_DIR}/tools/tests/${SOURCE}"
--build "${CMAKE_BINARY_DIR}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tools/tests/")
endif()
endmacro(ADD_OSQUERY_PYTHON_TEST)
# Add a static or dynamic link to libosquery.a (the core library)
macro(ADD_OSQUERY_LINK_CORE LINK)
ADD_OSQUERY_LINK(TRUE ${LINK} ${ARGN})
endmacro(ADD_OSQUERY_LINK_CORE)
# Add a static or dynamic link to libosquery_additional.a (the non-sdk library)
macro(ADD_OSQUERY_LINK_ADDITIONAL LINK)
ADD_OSQUERY_LINK(FALSE ${LINK} ${ARGN})
endmacro(ADD_OSQUERY_LINK_ADDITIONAL)
# Core/non core link helping macros (tell the build to link ALL).
macro(ADD_OSQUERY_LINK IS_CORE LINK)
if(${IS_CORE})
ADD_OSQUERY_LINK_INTERNAL("${LINK}" "${ARGN}" OSQUERY_LINKS)
elseif(NOT OSQUERY_BUILD_SDK_ONLY)
ADD_OSQUERY_LINK_INTERNAL("${LINK}" "${ARGN}" OSQUERY_ADDITIONAL_LINKS)
endif()
endmacro(ADD_OSQUERY_LINK)
macro(ADD_OSQUERY_LINK_INTERNAL LINK LINK_PATHS LINK_SET)
# The relative linking set is used for static libraries.
set(LINK_PATHS_RELATIVE
"${BUILD_DEPS}/lib"
${LINK_PATHS}
${OS_LIB_DIRS}
"$ENV{HOME}"
)
# The system linking set is for legacy ABI compatibility links and libraries
# known to exist on the system.
set(LINK_PATHS_SYSTEM
${LINK_PATHS}
"${BUILD_DEPS}/legacy/lib"
)
if(LINUX)
# Allow the build to search the 'default' dependency home for libgcc_s.
list(APPEND LINK_PATHS_SYSTEM "${BUILD_DEPS}/lib")
endif()
# The OS library paths are very important for system linking.
list(APPEND LINK_PATHS_SYSTEM ${OS_LIB_DIRS})
if(NOT "${LINK}" MATCHES "(^[-/].*)")
string(REPLACE " " ";" ITEMS "${LINK}")
foreach(ITEM ${ITEMS})
if(NOT DEFINED ${${ITEM}_library})
if("${ITEM}" MATCHES "(^lib.*)" OR "${ITEM}" MATCHES "(.*lib$)" OR DEFINED ENV{BUILD_LINK_SHARED})
# Use a system-provided library
set(ITEM_SYSTEM TRUE)
else()
set(ITEM_SYSTEM FALSE)
endif()
if(NOT ${ITEM_SYSTEM})
find_library("${ITEM}_library"
NAMES
"${ITEM}.lib"
"lib${ITEM}.lib"
"lib${ITEM}-mt.a"
"lib${ITEM}.a"
"${ITEM}"
HINTS ${LINK_PATHS_RELATIVE})
else()
find_library("${ITEM}_library"
NAMES
"${ITEM}.lib"
"lib${ITEM}.lib"
"lib${ITEM}-mt.so"
"lib${ITEM}.so"
"lib${ITEM}-mt.dylib"
"lib${ITEM}.dylib"
"${ITEM}-mt.so"
"${ITEM}.so"
"${ITEM}-mt.dylib"
"${ITEM}.dylib"
"${ITEM}"
HINTS ${LINK_PATHS_SYSTEM})
endif()
LOG_LIBRARY(${ITEM} "${${ITEM}_library}")
if("${${ITEM}_library}" STREQUAL "${ITEM}_library-NOTFOUND")
WARNING_LOG("Dependent library '${ITEM}' not found")
list(APPEND ${LINK_SET} ${ITEM})
else()
list(APPEND ${LINK_SET} "${${ITEM}_library}")
endif()
endif()
if("${${ITEM}_library}" MATCHES "/usr/local/lib.*")
if(NOT FREEBSD)
WARNING_LOG("Dependent library '${ITEM}' installed locally (beware!)")
endif()
endif()
endforeach()
else()
list(APPEND ${LINK_SET} ${LINK})
endif()
set(${LINK_SET} "${${LINK_SET}}" PARENT_SCOPE)
endmacro(ADD_OSQUERY_LINK_INTERNAL)
# Add a test and sources for components in libosquery.a (the core library)
macro(ADD_OSQUERY_TEST_CORE)
ADD_OSQUERY_TEST(TRUE ${ARGN})
endmacro(ADD_OSQUERY_TEST_CORE)
# Add a test and sources for components in libosquery_additional.a (the non-sdk library)
macro(ADD_OSQUERY_TEST_ADDITIONAL)
ADD_OSQUERY_TEST(FALSE ${ARGN})
endmacro(ADD_OSQUERY_TEST_ADDITIONAL)
# Core/non core test names and sources macros.
macro(ADD_OSQUERY_TEST IS_CORE)
if(NOT SKIP_TESTS AND (${IS_CORE} OR NOT OSQUERY_BUILD_SDK_ONLY))
if(${IS_CORE})
list(APPEND OSQUERY_TESTS ${ARGN})
set(OSQUERY_TESTS ${OSQUERY_TESTS} PARENT_SCOPE)
else()
list(APPEND OSQUERY_ADDITIONAL_TESTS ${ARGN})
set(OSQUERY_ADDITIONAL_TESTS ${OSQUERY_ADDITIONAL_TESTS} PARENT_SCOPE)
endif()
endif()
endmacro(ADD_OSQUERY_TEST)
macro(ADD_OSQUERY_TABLE_TEST)
if(NOT SKIP_TESTS AND NOT OSQUERY_BUILD_SDK_ONLY)
list(APPEND OSQUERY_TABLES_TESTS ${ARGN})
set(OSQUERY_TABLES_TESTS ${OSQUERY_TABLES_TESTS} PARENT_SCOPE)
endif()
endmacro(ADD_OSQUERY_TABLE_TEST)
# Add kernel test macro.
macro(ADD_OSQUERY_KERNEL_TEST)
if(NOT SKIP_TESTS)
list(APPEND OSQUERY_KERNEL_TESTS ${ARGN})
set(OSQUERY_KERNEL_TESTS ${OSQUERY_KERNEL_TESTS} PARENT_SCOPE)
endif()
endmacro(ADD_OSQUERY_KERNEL_TEST)
# Add benchmark macro.
macro(ADD_OSQUERY_BENCHMARK)
if(NOT SKIP_TESTS)
list(APPEND OSQUERY_BENCHMARKS ${ARGN})
set(OSQUERY_BENCHMARKS ${OSQUERY_BENCHMARKS} PARENT_SCOPE)
endif()
endmacro(ADD_OSQUERY_BENCHMARK)
# Add kernel benchmark macro.
macro(ADD_OSQUERY_KERNEL_BENCHMARK)
if(NOT SKIP_TESTS)
list(APPEND OSQUERY_KERNEL_BENCHMARKS ${ARGN})
set(OSQUERY_KERNEL_BENCHMARKS ${OSQUERY_KERNEL_BENCHMARKS} PARENT_SCOPE)
endif()
endmacro(ADD_OSQUERY_KERNEL_BENCHMARK)
# Add sources to libosquery.a (the core library)
macro(ADD_OSQUERY_LIBRARY_CORE TARGET)
ADD_OSQUERY_LIBRARY(TRUE ${TARGET} ${ARGN})
endmacro(ADD_OSQUERY_LIBRARY_CORE)
# Add sources to libosquery_additional.a (the non-sdk library)
macro(ADD_OSQUERY_LIBRARY_ADDITIONAL TARGET)
ADD_OSQUERY_LIBRARY(FALSE ${TARGET} ${ARGN})
endmacro(ADD_OSQUERY_LIBRARY_ADDITIONAL)
# Core/non core lists of target source files.
macro(ADD_OSQUERY_LIBRARY IS_CORE TARGET)
if(${IS_CORE} OR NOT OSQUERY_BUILD_SDK_ONLY)
foreach(SOURCE_FILE ${ARGN})
set(EXT_POSITION -1)
string(FIND "${SOURCE_FILE}" ".mm" EXT_POSITION)
if(EXT_POSITION GREATER 0)
SET_SOURCE_FILES_PROPERTIES("${SOURCE_FILE}"
PROPERTIES COMPILE_FLAGS ${OBJCXX_COMPILE_FLAGS})
endif()
endforeach()
add_library(${TARGET} OBJECT ${ARGN})
add_dependencies(${TARGET} osquery_extensions)
if(${IS_CORE})
list(APPEND OSQUERY_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_SOURCES ${OSQUERY_SOURCES} PARENT_SCOPE)
else()
list(APPEND OSQUERY_ADDITIONAL_SOURCES $<TARGET_OBJECTS:${TARGET}>)
set(OSQUERY_ADDITIONAL_SOURCES ${OSQUERY_ADDITIONAL_SOURCES} PARENT_SCOPE)
endif()
endif()
endmacro(ADD_OSQUERY_LIBRARY TARGET)
macro(ADD_OSQUERY_EXTENSION TARGET)
add_executable(${TARGET} ${ARGN})
TARGET_OSQUERY_LINK_WHOLE(${TARGET} libosquery)
set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME "${TARGET}.ext")
endmacro(ADD_OSQUERY_EXTENSION)
# Helper to abstract OS/Compiler whole linking.
macro(TARGET_OSQUERY_LINK_WHOLE TARGET OSQUERY_LIB)
if(WINDOWS)
target_link_libraries(${TARGET} "${OS_WHOLELINK_PRE}$<TARGET_FILE_NAME:${OSQUERY_LIB}>")
target_link_libraries(${TARGET} ${OSQUERY_LIB})
else()
target_link_libraries(${TARGET} "${OS_WHOLELINK_PRE}")
target_link_libraries(${TARGET} ${OSQUERY_LIB})
target_link_libraries(${TARGET} "${OS_WHOLELINK_POST}")
endif()
endmacro(TARGET_OSQUERY_LINK_WHOLE)
set(GLOBAL PROPERTY AMALGAMATE_TARGETS "")
macro(GET_GENERATION_DEPS BASE_PATH)
# Depend on the generation code.
set(GENERATION_DEPENDENCIES "")
file(GLOB TABLE_FILES_TEMPLATES "${BASE_PATH}/tools/codegen/templates/*.in")
file(GLOB CODEGEN_PYTHON_FILES "${BASE_PATH}/tools/codegen/*.py")
set(GENERATION_DEPENDENCIES
"${BASE_PATH}/specs/blacklist"
)
list(APPEND GENERATION_DEPENDENCIES ${CODEGEN_PYTHON_FILES})
list(APPEND GENERATION_DEPENDENCIES ${TABLE_FILES_TEMPLATES})
endmacro()
# Find and generate table plugins from .table syntax
macro(GENERATE_TABLES TABLES_PATH)
# Get all matching files for all platforms.
set(TABLES_SPECS "${TABLES_PATH}/specs")
set(TABLE_CATEGORIES "")
if(APPLE)
list(APPEND TABLE_CATEGORIES "darwin" "posix" "macwin")
elseif(FREEBSD)
list(APPEND TABLE_CATEGORIES "freebsd" "posix")
elseif(LINUX)
list(APPEND TABLE_CATEGORIES "linux" "posix")
elseif(WINDOWS)
list(APPEND TABLE_CATEGORIES "windows" "macwin")
else()
message( FATAL_ERROR "Unknown platform detected, cannot generate tables")
endif()
# Features optionally disabled.
if(NOT SKIP_LLDPD AND NOT WINDOWS)
list(APPEND TABLE_CATEGORIES "lldpd")
endif()
if(NOT SKIP_YARA AND NOT WINDOWS)
list(APPEND TABLE_CATEGORIES "yara")
endif()
if(NOT SKIP_TSK AND NOT WINDOWS)
list(APPEND TABLE_CATEGORIES "sleuthkit")
endif()
file(GLOB TABLE_FILES "${TABLES_SPECS}/*.table")
set(TABLE_FILES_FOREIGN "")
file(GLOB ALL_CATEGORIES RELATIVE "${TABLES_SPECS}" "${TABLES_SPECS}/*")
foreach(CATEGORY ${ALL_CATEGORIES})
if(IS_DIRECTORY "${TABLES_SPECS}/${CATEGORY}" AND NOT "${CATEGORY}" STREQUAL "utility")
file(GLOB TABLE_FILES_PLATFORM "${TABLES_SPECS}/${CATEGORY}/*.table")
list(FIND TABLE_CATEGORIES "${CATEGORY}" INDEX)
if(${INDEX} EQUAL -1)
# Append inner tables to foreign
list(APPEND TABLE_FILES_FOREIGN ${TABLE_FILES_PLATFORM})
else()
# Append inner tables to TABLE_FILES.
list(APPEND TABLE_FILES ${TABLE_FILES_PLATFORM})
endif()
endif()
endforeach()
# Generate a set of targets, comprised of table spec file.
get_property(TARGETS GLOBAL PROPERTY AMALGAMATE_TARGETS)
set(NEW_TARGETS "")
foreach(TABLE_FILE ${TABLE_FILES})
list(FIND TARGETS "${TABLE_FILE}" INDEX)
if (${INDEX} EQUAL -1)
# Do not set duplicate targets.
list(APPEND NEW_TARGETS "${TABLE_FILE}")
endif()
endforeach()
set_property(GLOBAL PROPERTY AMALGAMATE_TARGETS "${NEW_TARGETS}")
set_property(GLOBAL PROPERTY AMALGAMATE_FOREIGN_TARGETS "${TABLE_FILES_FOREIGN}")
endmacro()
macro(GENERATE_UTILITIES TABLES_PATH)
file(GLOB TABLE_FILES_UTILITY "${TABLES_PATH}/specs/utility/*.table")
set_property(GLOBAL APPEND PROPERTY AMALGAMATE_TARGETS "${TABLE_FILES_UTILITY}")
endmacro(GENERATE_UTILITIES)
macro(GENERATE_TABLE TABLE_FILE FOREIGN NAME BASE_PATH OUTPUT)
GET_GENERATION_DEPS(${BASE_PATH})
set(TABLE_FILE_GEN "${TABLE_FILE}")
string(REGEX REPLACE
".*/specs.*/(.*)\\.table"
"${CMAKE_BINARY_DIR}/generated/tables_${NAME}/\\1.cpp"
TABLE_FILE_GEN
${TABLE_FILE_GEN}
)
add_custom_command(
OUTPUT "${TABLE_FILE_GEN}"
COMMAND "${PYTHON_EXECUTABLE}"
"${BASE_PATH}/tools/codegen/gentable.py"
"${FOREIGN}"
"${TABLE_FILE}"
"${TABLE_FILE_GEN}"
DEPENDS ${TABLE_FILE} ${GENERATION_DEPENDENCIES}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
list(APPEND ${OUTPUT} "${TABLE_FILE_GEN}")
endmacro(GENERATE_TABLE)
macro(AMALGAMATE BASE_PATH NAME OUTPUT)
GET_GENERATION_DEPS(${BASE_PATH})
if("${NAME}" STREQUAL "foreign")
get_property(TARGETS GLOBAL PROPERTY AMALGAMATE_FOREIGN_TARGETS)
set(FOREIGN "--foreign")
else()
get_property(TARGETS GLOBAL PROPERTY AMALGAMATE_TARGETS)
endif()
set(GENERATED_TARGETS "")
foreach(TARGET ${TARGETS})
GENERATE_TABLE("${TARGET}" "${FOREIGN}" "${NAME}" "${BASE_PATH}" GENERATED_TARGETS)
endforeach()
# Include the generated folder in make clean.
set_directory_properties(PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_BINARY_DIR}/generated")
# Append all of the code to a single amalgamation.
set(AMALGAMATION_FILE_GEN "${CMAKE_BINARY_DIR}/generated/${NAME}_amalgamation.cpp")
add_custom_command(
OUTPUT ${AMALGAMATION_FILE_GEN}
COMMAND "${PYTHON_EXECUTABLE}"
"${BASE_PATH}/tools/codegen/amalgamate.py"
"${FOREIGN}"
"${BASE_PATH}/tools/codegen/"
"${CMAKE_BINARY_DIR}/generated"
"${NAME}"
DEPENDS ${GENERATED_TARGETS} ${GENERATION_DEPENDENCIES}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
set(${OUTPUT} ${AMALGAMATION_FILE_GEN})
set_property(GLOBAL PROPERTY AMALGAMATE_TARGETS "")
endmacro(AMALGAMATE)
function(JOIN VALUES GLUE OUTPUT)
string(REPLACE ";" "${GLUE}" _TMP_STR "${VALUES}")
set(${OUTPUT} "${_TMP_STR}" PARENT_SCOPE)
endfunction(JOIN)