cmake_minimum_required(VERSION 3.16) if(WIN32) project(fn_registry_cpp LANGUAGES C CXX RC) else() project(fn_registry_cpp LANGUAGES C CXX) endif() set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # --- Options --- option(TRACY_ENABLE "Enable Tracy profiling" OFF) option(FN_BUILD_TESTS "Build C++ e2e tests with Dear ImGui Test Engine" OFF) # --- Vendor: Dear ImGui --- set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/imgui) add_library(imgui STATIC ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp ) target_include_directories(imgui PUBLIC ${IMGUI_DIR} ${IMGUI_DIR}/backends ) # When tests are enabled, imgui must be compiled with hooks for the test engine. # The hooks compile to no-ops if the engine is never started, so this is safe to # leave on but we still gate it to keep release builds identical to today. if(FN_BUILD_TESTS) target_compile_definitions(imgui PUBLIC IMGUI_ENABLE_TEST_ENGINE) endif() # --- Vendor: Dear ImGui Test Engine (opt-in via FN_BUILD_TESTS) --- # Personal/open-source license (see vendor/imgui_test_engine/LICENSE.txt). if(FN_BUILD_TESTS) set(IMTE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/imgui_test_engine) add_library(imgui_test_engine STATIC ${IMTE_DIR}/imgui_te_engine.cpp ${IMTE_DIR}/imgui_te_context.cpp ${IMTE_DIR}/imgui_te_coroutine.cpp ${IMTE_DIR}/imgui_te_exporters.cpp ${IMTE_DIR}/imgui_te_perftool.cpp ${IMTE_DIR}/imgui_te_ui.cpp ${IMTE_DIR}/imgui_te_utils.cpp ${IMTE_DIR}/imgui_capture_tool.cpp ) target_include_directories(imgui_test_engine PUBLIC ${IMTE_DIR} ${IMTE_DIR}/thirdparty ) # Use std::thread for coroutines so apps don't have to provide their own. target_compile_definitions(imgui_test_engine PUBLIC IMGUI_ENABLE_TEST_ENGINE IMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL=1 IMGUI_TEST_ENGINE_ENABLE_STD_FUNCTION=1 ) target_link_libraries(imgui_test_engine PUBLIC imgui) if(UNIX) find_package(Threads REQUIRED) target_link_libraries(imgui_test_engine PUBLIC Threads::Threads) endif() endif() # --- Vendor: ImPlot --- set(IMPLOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/implot) add_library(implot STATIC ${IMPLOT_DIR}/implot.cpp ${IMPLOT_DIR}/implot_items.cpp ) target_include_directories(implot PUBLIC ${IMPLOT_DIR}) target_link_libraries(implot PUBLIC imgui) # --- Vendor: ImPlot3D --- # Pinned to v0.4 (commit 41ae3e447c0de20ecab95d38a4b4dc0835a3efc2). # See cpp/vendor/implot3d.VENDORING.md for update procedure. set(IMPLOT3D_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/implot3d) add_library(implot3d STATIC ${IMPLOT3D_DIR}/implot3d.cpp ${IMPLOT3D_DIR}/implot3d_items.cpp ${IMPLOT3D_DIR}/implot3d_meshes.cpp ) target_include_directories(implot3d PUBLIC ${IMPLOT3D_DIR}) target_link_libraries(implot3d PUBLIC imgui) # --- Vendor: Tracy (optional) --- if(TRACY_ENABLE) set(TRACY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/tracy) add_library(tracy STATIC ${TRACY_DIR}/public/TracyClient.cpp ) target_include_directories(tracy PUBLIC ${TRACY_DIR}/public) target_compile_definitions(tracy PUBLIC TRACY_ENABLE) endif() # --- Vendor: imgui-node-editor --- set(NODE_EDITOR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/imgui-node-editor) add_library(imgui_node_editor STATIC ${NODE_EDITOR_DIR}/imgui_node_editor.cpp ${NODE_EDITOR_DIR}/imgui_node_editor_api.cpp ${NODE_EDITOR_DIR}/imgui_canvas.cpp ${NODE_EDITOR_DIR}/crude_json.cpp ) target_include_directories(imgui_node_editor PUBLIC ${NODE_EDITOR_DIR}) target_link_libraries(imgui_node_editor PUBLIC imgui) # --- Platform dependencies --- if(CMAKE_SYSTEM_NAME STREQUAL "Windows") # Cross-compile: use vendored or system GLFW, link opengl32/gdi32 find_package(glfw3 QUIET) if(NOT glfw3_FOUND) # Build GLFW from source if available if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vendor/glfw/CMakeLists.txt) set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) add_subdirectory(vendor/glfw) else() message(FATAL_ERROR "GLFW not found. For Windows cross-compile, add GLFW source to cpp/vendor/glfw/") endif() endif() set(PLATFORM_LIBS glfw opengl32 gdi32 imm32) else() # Linux native find_package(glfw3 REQUIRED) find_package(OpenGL REQUIRED) set(PLATFORM_LIBS glfw OpenGL::GL ${CMAKE_DL_LIBS}) endif() target_link_libraries(imgui PUBLIC ${PLATFORM_LIBS}) # --- SQLite3 (shared by every app that uses it, including fn_framework for # layout_storage) --- # System on Linux, vendored amalgamation on Windows cross-compile. find_package(SQLite3 QUIET) if(NOT SQLite3_FOUND AND NOT TARGET sqlite3_vendored) set(SQLITE3_AMALG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/sqlite3) add_library(sqlite3_vendored STATIC ${SQLITE3_AMALG_DIR}/sqlite3.c) target_include_directories(sqlite3_vendored PUBLIC ${SQLITE3_AMALG_DIR}) target_compile_definitions(sqlite3_vendored PRIVATE SQLITE_THREADSAFE=1 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_JSON1 ) add_library(SQLite::SQLite3 ALIAS sqlite3_vendored) endif() # --- DuckDB (precompiled libs — see cpp/vendor/duckdb/README.md) --- # Header en vendor/duckdb/include/. Lib dinamica en linux/ o windows/ segun # el target. Las libs estan gitignored — ejecutar # `cpp/vendor/duckdb/download_duckdb.sh` la primera vez. if(NOT TARGET duckdb_vendored) set(DUCKDB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/duckdb) if(WIN32) set(DUCKDB_LIB ${DUCKDB_DIR}/windows/duckdb.lib) set(DUCKDB_RUNTIME ${DUCKDB_DIR}/windows/duckdb.dll) else() set(DUCKDB_LIB ${DUCKDB_DIR}/linux/libduckdb.so) set(DUCKDB_RUNTIME ${DUCKDB_DIR}/linux/libduckdb.so) endif() if(NOT EXISTS ${DUCKDB_LIB}) message(WARNING "[duckdb] ${DUCKDB_LIB} no existe — corre cpp/vendor/duckdb/download_duckdb.sh") endif() add_library(duckdb_vendored INTERFACE) target_include_directories(duckdb_vendored INTERFACE ${DUCKDB_DIR}/include) target_link_libraries(duckdb_vendored INTERFACE ${DUCKDB_LIB}) add_library(DuckDB::DuckDB ALIAS duckdb_vendored) # Helper para que las apps copien la runtime lib al lado del exe. # add_imgui_app puede invocarlo, o cada app lo hace en su CMakeLists. function(duckdb_copy_runtime target) if(EXISTS ${DUCKDB_RUNTIME}) add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DUCKDB_RUNTIME} $ COMMENT "Copying DuckDB runtime next to ${target}") endif() endfunction() endif() # --- Framework --- # Incluye tokens.cpp (identidad visual Mantine dark + indigo), icon_font.cpp # (Karla/Roboto/... + Tabler), app_settings.cpp (persistencia y ventana de # settings) y fps_overlay.cpp (overlay opcional). Ver cpp/DESIGN_SYSTEM.md add_library(fn_framework STATIC framework/app_base.cpp functions/core/tokens.cpp functions/core/icon_font.cpp functions/core/app_settings.cpp functions/core/app_about.cpp functions/core/fps_overlay.cpp functions/core/panel_menu.cpp functions/core/layouts_menu.cpp functions/core/app_menubar.cpp functions/core/logger.cpp functions/core/log_window.cpp functions/gfx/gl_loader.cpp functions/core/layout_storage.cpp functions/core/selectable_text.cpp ) target_include_directories(fn_framework PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/framework ${CMAKE_CURRENT_SOURCE_DIR}/functions ) # FN_CPP_ROOT permite que icon_font.cpp localice vendor/tabler-icons/tabler-icons.ttf # en builds de desarrollo desde el repo (en deploys, la TTF se copia junto al exe). target_compile_definitions(fn_framework PUBLIC FN_CPP_ROOT="${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries(fn_framework PUBLIC imgui implot implot3d SQLite::SQLite3) if(TRACY_ENABLE) target_link_libraries(fn_framework PUBLIC tracy) endif() if(FN_BUILD_TESTS) # Public so apps that include fn_framework headers see the same hooks. target_compile_definitions(fn_framework PUBLIC IMGUI_ENABLE_TEST_ENGINE) target_link_libraries(fn_framework PUBLIC imgui_test_engine) endif() # --- OpenMP (opcional) --- # Habilita #pragma omp en las funciones del registry que lo declaren bajo # guardia _OPENMP. Si el compilador no lo soporta (no debiera, gcc/clang # y mingw-w64 lo traen), los pragmas se ignoran sin romper el build. find_package(OpenMP QUIET) if(OpenMP_CXX_FOUND) target_link_libraries(fn_framework PUBLIC OpenMP::OpenMP_CXX) message(STATUS "OpenMP enabled for fn_framework (${OpenMP_CXX_VERSION})") else() message(STATUS "OpenMP NOT found — force layout fallback to single-thread") endif() # --- Macro for creating ImGui apps --- # Capturamos la raiz del modulo cpp/ para que add_imgui_app la use desde # subdirectorios (donde CMAKE_CURRENT_SOURCE_DIR apunta al app, no al root). set(FN_CPP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "fn_registry cpp root") function(add_imgui_app target) # Windows icon: si la app tiene /appicon.ico, generamos un .rc # apuntando a ese .ico y lo anadimos como fuente. mingw-w64 windres # (CMAKE_RC_COMPILER en la toolchain) lo enlaza en el .exe. set(_extra_sources "") if(WIN32 AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/appicon.ico) set(_rc_file ${CMAKE_CURRENT_BINARY_DIR}/${target}_appicon.rc) # Forward slashes para que windres no se confunda con escapes. file(TO_CMAKE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/appicon.ico _ico_path) file(WRITE ${_rc_file} "IDI_ICON1 ICON \"${_ico_path}\"\n") list(APPEND _extra_sources ${_rc_file}) endif() add_executable(${target} ${ARGN} ${_extra_sources}) target_link_libraries(${target} PRIVATE fn_framework) target_include_directories(${target} PRIVATE ${FN_CPP_ROOT_DIR}/functions ) # Convencion de layout (cpp_apps.md §7): # /.exe + .dll (binario + DLLs Windows convention) # /assets/ (read-only: ttfs, enrichers, runtime, etc.) # /local_files/ (creado en runtime: ini, db, projects) # # add_imgui_app copia las TTFs a /assets/. La app las # encuentra en runtime via fn::asset_path() (icon_font.cpp). set(_ASSETS_DIR $/assets) add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${_ASSETS_DIR} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FN_CPP_ROOT_DIR}/vendor/imgui/misc/fonts/Karla-Regular.ttf ${_ASSETS_DIR}/Karla-Regular.ttf COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FN_CPP_ROOT_DIR}/vendor/imgui/misc/fonts/Roboto-Medium.ttf ${_ASSETS_DIR}/Roboto-Medium.ttf COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FN_CPP_ROOT_DIR}/vendor/imgui/misc/fonts/DroidSans.ttf ${_ASSETS_DIR}/DroidSans.ttf COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FN_CPP_ROOT_DIR}/vendor/imgui/misc/fonts/Cousine-Regular.ttf ${_ASSETS_DIR}/Cousine-Regular.ttf COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FN_CPP_ROOT_DIR}/vendor/tabler-icons/tabler-icons.ttf ${_ASSETS_DIR}/tabler-icons.ttf VERBATIM ) endfunction() # --- Function libraries (headers for composition) --- # Functions are compiled as part of apps that use them via add_imgui_app. # Each function is a .h/.cpp pair included by the app's CMakeLists.txt. # --- fn_table_viz: static lib bundling all Wave 1+2 tables-stack functions --- # Issue 0081-I. Apps consumidores: target_link_libraries( PRIVATE fn_table_viz). # data_table.cpp references playground-local headers (llm_anthropic.h, tql_to_sql.h, # tql.h, data_table_logic.h). These are NOT available in the registry build — they # live in the playground. fn_table_viz excludes data_table.cpp intentionally until # those playground dependencies are promoted to the registry (Wave 4 deuda). # The remaining 9 .cpp files compile cleanly with only registry headers. if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vendor/lua/CMakeLists.txt) add_library(fn_table_viz STATIC ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/compute_stage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/compute_pipeline.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/tql_emit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/tql_helpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/tql_apply.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/tql_to_sql.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/lua_engine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/join_tables.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/auto_detect_type.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/compute_column_stats.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/core/llm_anthropic.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/viz/viz_render.cpp ${CMAKE_CURRENT_SOURCE_DIR}/functions/viz/data_table.cpp ) target_include_directories(fn_table_viz PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/functions ) target_include_directories(fn_table_viz PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/framework ) target_compile_definitions(fn_table_viz PUBLIC FN_LLM_ANTHROPIC=1) target_link_libraries(fn_table_viz PUBLIC imgui implot lua54 ) # fn::local_path() used by data_table.cpp (Ask AI export path + TQL save/load). # fn_framework provides the implementation; link it here. target_link_libraries(fn_table_viz PRIVATE fn_framework) endif() # --- Demo app (lives in apps/, issue 0096 standardization) --- if(NOT DEFINED _CHART_DEMO_DIR) set(_CHART_DEMO_DIR ${CMAKE_SOURCE_DIR}/../apps/chart_demo) endif() if(EXISTS ${_CHART_DEMO_DIR}/CMakeLists.txt) add_subdirectory(${_CHART_DEMO_DIR} ${CMAKE_BINARY_DIR}/apps/chart_demo) endif() # --- Shaders Lab (lives in apps/) --- if(NOT DEFINED _SHADERS_LAB_DIR) set(_SHADERS_LAB_DIR ${CMAKE_SOURCE_DIR}/../apps/shaders_lab) endif() if(EXISTS ${_SHADERS_LAB_DIR}/CMakeLists.txt) add_subdirectory(${_SHADERS_LAB_DIR} ${CMAKE_BINARY_DIR}/apps/shaders_lab) endif() # --- Lua 5.4 vendored (para playground tables / DSL formulas) --- if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vendor/lua/CMakeLists.txt) add_subdirectory(vendor/lua) endif() # --- Primitives Gallery (lives in apps/) --- if(NOT DEFINED _PG_DIR) set(_PG_DIR ${CMAKE_SOURCE_DIR}/../apps/primitives_gallery) endif() if(EXISTS ${_PG_DIR}/CMakeLists.txt) add_subdirectory(${_PG_DIR} ${CMAKE_BINARY_DIR}/apps/primitives_gallery) endif() # --- Tables playground (vive dentro de primitives_gallery/playground/tables/) --- if(EXISTS ${_PG_DIR}/playground/tables/CMakeLists.txt) add_subdirectory(${_PG_DIR}/playground/tables ${CMAKE_BINARY_DIR}/apps/primitives_gallery/playground/tables) endif() # --- text_editor + file_watcher smoke test (lives in apps/) --- if(NOT DEFINED _TES_DIR) set(_TES_DIR ${CMAKE_SOURCE_DIR}/../apps/text_editor_smoke) endif() if(EXISTS ${_TES_DIR}/CMakeLists.txt) add_subdirectory(${_TES_DIR} ${CMAKE_BINARY_DIR}/apps/text_editor_smoke) endif() # --- AltSnap viewport-jitter regression test (lives in apps/) --- if(NOT DEFINED _AJT_DIR) set(_AJT_DIR ${CMAKE_SOURCE_DIR}/../apps/altsnap_jitter_test) endif() if(EXISTS ${_AJT_DIR}/CMakeLists.txt) add_subdirectory(${_AJT_DIR} ${CMAKE_BINARY_DIR}/apps/altsnap_jitter_test) endif() # --- gamedev stack (SDL3 + sokol_gfx + miniaudio, issue 0072) --- # Apps standalone, no usan fn_framework. Vendor SDL3 se compila una vez aqui; # las apps solo linkan SDL3::SDL3-static. if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vendor/sdl3/CMakeLists.txt AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/vendor/sokol/sokol_gfx.h) set(SDL_SHARED OFF CACHE BOOL "" FORCE) set(SDL_STATIC ON CACHE BOOL "" FORCE) set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE) set(SDL_TESTS OFF CACHE BOOL "" FORCE) set(SDL_EXAMPLES OFF CACHE BOOL "" FORCE) set(SDL_INSTALL OFF CACHE BOOL "" FORCE) set(SDL_X11_XSCRNSAVER OFF CACHE BOOL "" FORCE) add_subdirectory(vendor/sdl3 EXCLUDE_FROM_ALL) if(NOT DEFINED _ES_DIR) set(_ES_DIR ${CMAKE_SOURCE_DIR}/../apps/engine_smoke) endif() if(EXISTS ${_ES_DIR}/CMakeLists.txt) add_subdirectory(${_ES_DIR} ${CMAKE_BINARY_DIR}/apps/engine_smoke) endif() if(NOT DEFINED _RT_DIR) set(_RT_DIR ${CMAKE_SOURCE_DIR}/../apps/runtime_test) endif() if(EXISTS ${_RT_DIR}/CMakeLists.txt) add_subdirectory(${_RT_DIR} ${CMAKE_BINARY_DIR}/apps/runtime_test) endif() endif() # --- Registry Dashboard (lives in projects/fn_monitoring/apps/) --- # _DASH_DIR puede sobreescribirse via -D_DASH_DIR= para apuntar a un # worktree (parallel-fix-issues u otros flujos que aislen builds). if(NOT DEFINED _DASH_DIR) set(_DASH_DIR ${CMAKE_SOURCE_DIR}/../projects/fn_monitoring/apps/registry_dashboard) endif() if(EXISTS ${_DASH_DIR}/CMakeLists.txt) add_subdirectory(${_DASH_DIR} ${CMAKE_BINARY_DIR}/apps/registry_dashboard) endif() # --- Graph Explorer (lives in projects/osint_graph/apps/) --- # _GE_DIR puede sobreescribirse via -D_GE_DIR= para apuntar a un # worktree (parallel-fix-issues u otros flujos que aislen builds). if(NOT DEFINED _GE_DIR) set(_GE_DIR ${CMAKE_SOURCE_DIR}/../projects/osint_graph/apps/graph_explorer) endif() if(EXISTS ${_GE_DIR}/CMakeLists.txt) add_subdirectory(${_GE_DIR} ${CMAKE_BINARY_DIR}/apps/graph_explorer) endif() # --- odr_console (lives in projects/online_data_recopilation/apps/) --- if(NOT DEFINED _ODR_DIR) set(_ODR_DIR ${CMAKE_SOURCE_DIR}/../projects/online_data_recopilation/apps/odr_console) endif() if(EXISTS ${_ODR_DIR}/CMakeLists.txt) add_subdirectory(${_ODR_DIR} ${CMAKE_BINARY_DIR}/apps/odr_console) endif() # --- navegator_dashboard (lives in projects/navegator/apps/) --- # Windows-only — el propio CMakeLists.txt hace return() en non-WIN32. if(NOT DEFINED _NAVD_DIR) set(_NAVD_DIR ${CMAKE_SOURCE_DIR}/../projects/navegator/apps/navegator_dashboard) endif() if(EXISTS ${_NAVD_DIR}/CMakeLists.txt) add_subdirectory(${_NAVD_DIR} ${CMAKE_BINARY_DIR}/apps/navegator_dashboard) endif() # --- Tests (Catch2 amalgamated, ctest-driven) --- option(BUILD_TESTING "Build C++ tests" ON) if(BUILD_TESTING) enable_testing() add_subdirectory(tests) endif() # --- dag_engine_ui (lives in apps/, issue 0096) --- if(NOT DEFINED _DAG_UI_DIR) set(_DAG_UI_DIR ${CMAKE_SOURCE_DIR}/../apps/dag_engine_ui) endif() if(EXISTS ${_DAG_UI_DIR}/CMakeLists.txt) add_subdirectory(${_DAG_UI_DIR} ${CMAKE_BINARY_DIR}/apps/dag_engine_ui) endif() # --- data_factory (lives in apps/, issue 0096) --- set(_DATA_FACTORY_DIR ${CMAKE_SOURCE_DIR}/../apps/data_factory) if(EXISTS ${_DATA_FACTORY_DIR}/CMakeLists.txt) add_subdirectory(${_DATA_FACTORY_DIR} ${CMAKE_BINARY_DIR}/apps/data_factory) endif()