configure_file(config.h.in config.h)

# Use position independent code for all targets in this directory
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

add_library(allreduce allreduce_sockets.cc allreduce_threads.cc vw_exception.cc)
target_include_directories(allreduce PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

add_library(VowpalWabbit::allreduce ALIAS allreduce)

# Winsock32 should be available on Windows
if(WIN32)
  target_link_libraries(allreduce PUBLIC wsock32 ws2_32)
else()
  target_compile_options(allreduce PUBLIC ${linux_flags})
endif()

set(vw_all_headers
accumulate.h action_score.h active_cover.h active.h allreduce.h array_parameters_dense.h
array_parameters.h audit_regressor.h autolink.h baseline.h beam.h best_constant.h bfgs.h binary.h
boosting.h bs.h cache.h cb_adf.h cb_algs.h cb_explore_adf_bag.h cb_explore_adf_common.h
cb_explore_adf_cover.h cb_explore_adf_first.h cb_explore_adf_greedy.h cb_explore_adf_regcb.h
cb_explore_adf_softmax.h cb_explore.h cb.h cbify.h ccb_label.h classweight.h comp_io.h
conditional_contextual_bandit.h confidence.h config.h.in constant.h correctedMath.h cost_sensitive.h
crossplat_compat.h cs_active.h csoaa.h ect.h error_reporting.h example_predict.h example.h
explore_eval.h expreplay.h ezexample.h feature_group.h ftrl.h gd_mf.h gd_predict.h gd.h
gen_cs_example.h global_data.h hashstring.h interact.h interactions_predict.h interactions.h
io_buf.h kernel_svm.h label_dictionary.h label_parser.h lda_core.h learner.h log_multi.h
loss_functions.h lrq.h lrqfa.h marginal.h memory_tree.h memory.h mf.h multiclass.h multilabel_oaa.h
multilabel.h mwt.h network.h nn.h no_label.h noop.h oaa.h object_pool.h OjaNewton.h
options_boost_po.h options_serializer_boost_po.h options_types.h options.h parse_args.h
parse_dispatch_loop.h parse_example_json.h parse_example.h parse_primitives.h parse_regressor.h
parser.h primitives.h print.h queue.h rand48.h recall_tree.h reductions.h scorer.h
search_dep_parser.h search_entityrelationtask.h search_graph.h search_hooktask.h search_meta.h
search_multiclasstask.h search_sequencetask.h search.h sender.h shared_feature_merger.h
simple_label.h spanning_tree.h stable_unique.h stagewise_poly.h svrg.h topk.h unique_sort.h
v_array.h v_hashmap.h version.h vw_allreduce.h vw_exception.h vw_validate.h vw_versions.h vw.h
vwdll.h warm_cb.h
)

set(vw_all_sources
  accumulate.cc action_score.cc active_cover.cc active.cc audit_regressor.cc autolink.cc baseline.cc
  best_constant.cc bfgs.cc binary.cc boosting.cc bs.cc cache.cc cb_adf.cc cb_algs.cc
  cb_explore_adf_bag.cc cb_explore_adf_cover.cc cb_explore_adf_first.cc cb_explore_adf_greedy.cc
  cb_explore_adf_regcb.cc cb_explore_adf_softmax.cc cb_explore.cc cb_sample.cc cb.cc cbify.cc
  ccb_label.cc classweight.cc comp_io.cc conditional_contextual_bandit.cc confidence.cc
  cost_sensitive.cc cs_active.cc csoaa.cc ect.cc example.cc explore_eval.cc ftrl.cc gd_mf.cc gd.cc
  gen_cs_example.cc global_data.cc interact.cc interactions.cc io_buf.cc kernel_svm.cc
  label_dictionary.cc lda_core.cc learner.cc log_multi.cc loss_functions.cc lrq.cc lrqfa.cc
  marginal.cc memory_tree.cc mf.cc multiclass.cc multilabel_oaa.cc multilabel.cc mwt.cc network.cc
  nn.cc no_label.cc noop.cc oaa.cc OjaNewton.cc options_boost_po.cc options_serializer_boost_po.cc
  parse_args.cc parse_example.cc parse_primitives.cc parse_regressor.cc parser.cc print.cc rand48.cc
  recall_tree.cc scorer.cc search_dep_parser.cc search_entityrelationtask.cc search_graph.cc
  search_hooktask.cc search_meta.cc search_multiclasstask.cc search_sequencetask.cc search.cc
  sender.cc shared_feature_merger.cc simple_label.cc stagewise_poly.cc svrg.cc topk.cc unique_sort.cc
  version.cc vw_exception.cc vw_validate.cc warm_cb.cc
)

add_library(vw ${vw_all_sources} ${vw_all_headers})

target_link_libraries(vw
  PUBLIC
    VowpalWabbit::explore VowpalWabbit::allreduce
  PRIVATE
    Boost::program_options ${CMAKE_DL_LIBS} ${LINK_THREADS} ZLIB::ZLIB
    # Workaround an issue where RapidJSON needed to be exported tom install the target. This is
    # actually a private dependency and so do not "link" when processing targets for installation.
    # https://gitlab.kitware.com/cmake/cmake/issues/15415
    $<BUILD_INTERFACE:rapidjson>)

add_library(VowpalWabbit::vw ALIAS vw)

if(GCOV)
  target_link_libraries(vw PUBLIC gcov --coverage)
endif()

target_include_directories(vw PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

target_compile_definitions(vw PUBLIC _FILE_OFFSET_BITS=64 $<$<CONFIG:RELEASE>:NDEBUG>)
# Only define if Clang is not used
if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  target_compile_definitions(vw PUBLIC __extern_always_inline=inline)
endif()

# Clang-cl on Windows has issues with our usage of SIMD types. Turn it off explicitly for Windows + clang-cl to mitigate.
# See issue #
if(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  target_compile_definitions(vw PUBLIC VW_NO_INLINE_SIMD)
endif()

# TODO code analysis
if(WIN32)
  target_compile_definitions(vw PUBLIC __SSE2__)
  target_compile_options(vw PUBLIC /MP /Zc:__cplusplus)
else()
  target_compile_options(vw PUBLIC ${linux_flags})
endif()

# Turn on warnings
if(WARNINGS)
  if(MSVC)
    target_compile_options(vw PRIVATE /W4)
  else(MSVC)
    target_compile_options(vw PRIVATE -Wall -Wextra -Wpedantic)
  endif(MSVC)
endif(WARNINGS)

if(NOT WIN32)
  add_executable(active_interactor active_interactor.cc)

  if(GCOV)
    target_link_libraries(active_interactor PUBLIC gcov --coverage)
  endif()

  if(VW_INSTALL)
    install(
      TARGETS active_interactor
      EXPORT VowpalWabbitConfig
      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
  endif()

  target_compile_definitions(active_interactor PUBLIC _FILE_OFFSET_BITS=64)
  target_compile_definitions(active_interactor PUBLIC $<$<CONFIG:RELEASE>:NDEBUG>)
  target_compile_options(active_interactor PUBLIC ${linux_flags})

  find_file(HELP2MAN_EXECUTABLE help2man HINTS /bin /usr/bin /usr/local/bin)
  if (HELP2MAN_EXECUTABLE)
    add_custom_target(manpage ALL
      COMMAND ${HELP2MAN_EXECUTABLE}
        --no-info
        --name="Vowpal Wabbit -- fast online learning tool" $<TARGET_FILE:vw-bin>
        --output=$<TARGET_FILE:vw-bin>.1
      DEPENDS vw-bin)

      if(VW_INSTALL)
        install(FILES $<TARGET_FILE:vw-bin>.1 DESTINATION share/man/man1)
      endif()
  else()
    message(STATUS "help2man not found, please install it to generate manpages")
  endif()
endif()

# build main executable
add_executable(vw-bin main.cc)
target_link_libraries(vw-bin PRIVATE VowpalWabbit::vw Boost::program_options)
set_target_properties(vw-bin PROPERTIES OUTPUT_NAME vw)

if(STATIC_LINK_VW)
  target_link_libraries(vw-bin PRIVATE ${unix_static_flag})
endif()

# This is used by Travis to not build vw_c_wrapper, this required <codecvt> which became available in GCC 5.1
if(NOT DEFINED DO_NOT_BUILD_VW_C_WRAPPER)
  if(STATIC_LINK_VW)
    add_library(vw_c_wrapper vwdll.cpp)
  else()
    add_library(vw_c_wrapper SHARED vwdll.cpp)
  endif()

  add_library(VowpalWabbit::vw_c_wrapper ALIAS vw_c_wrapper)

  target_compile_definitions(vw_c_wrapper PUBLIC VWDLL_EXPORTS _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE ZLIB_WINAPI)
  target_link_libraries(vw_c_wrapper PUBLIC VowpalWabbit::vw)
  if(VW_INSTALL)
    install(
      TARGETS vw_c_wrapper
      EXPORT VowpalWabbitConfig
      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
  endif()
endif()

if(VW_INSTALL)
  install(
    TARGETS vw vw-bin allreduce
    EXPORT VowpalWabbitConfig
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

  # VW target headers
  install(
    FILES ${vw_all_headers} ${CMAKE_CURRENT_BINARY_DIR}/config.h
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/vowpalwabbit)
endif()
