option(BUILD_EXECUTABLE_QTPROFILER_STANDALONE
       "Creates an install target for standalone qtprofiler"
       OFF)

# On macOS qtprofiler is built as its own application bundle next to
# "Qt Creator.app" (instead of being buried inside its libexec directory), so
# it behaves like a standalone application with its own icon and Info.plist.
# The bundle (and its executable) use the "Qt Profiler" display name, while the
# target/identifier stays "qtprofiler".
set(qtprofiler_bundle_name "Qt Profiler")
set(qtprofiler_props "")
set(qtprofiler_destination "${IDE_LIBEXEC_PATH}")
if (APPLE)
  list(APPEND qtprofiler_props MACOSX_BUNDLE ON OUTPUT_NAME "${qtprofiler_bundle_name}")
  set(qtprofiler_destination "${IDE_APP_PATH}")
elseif (EMSCRIPTEN)
  # Emit the WebAssembly app (qtprofiler.html/js/wasm plus qtloader.js/qtlogo.svg) into a
  # flat directory at the build root instead of Qt Creator's libexec (which carries the
  # host's "Qt Creator.app/Contents/Resources" layout), so it is easy to serve/deploy.
  set(qtprofiler_destination "qtprofiler")
endif()

add_qtc_executable(qtprofiler
  CONDITION TARGET Profiler
  SKIP_INSTALL
  DEPENDS app_version Profiler CommonTraceFormat Tracing
  PROPERTIES ${qtprofiler_props}
  DESTINATION "${qtprofiler_destination}"
  SOURCES
    mainsidebar.cpp mainsidebar.h
    qtprofilerinit.cpp qtprofilerinit.h
    qtprofilermain.cpp
    qtprofilerrpc.cpp qtprofilerrpc.h
    qtprofilersettings.cpp qtprofilersettings.h
    qtprofilerwindow.h qtprofilerwindow.cpp
    schema/api.h
)

qtc_add_version_resource(qtprofiler "Qt Profiler")

# Turn it into a proper macOS application bundle: attach the Info.plist and the
# app icon, and make sure both end up in the build tree and in the install tree.
if (APPLE AND TARGET qtprofiler)
  if (CMAKE_OSX_DEPLOYMENT_TARGET)
    set(MACOSX_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET})
  endif()

  set_target_properties(qtprofiler PROPERTIES
    MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
  )

  # The call-stack sampler needs the debugger entitlement here just as much as in
  # Qt Creator itself, and refuses to offer itself without it (see src/app).
  qtc_sign_with_entitlements(qtprofiler
    "${QtCreator_SOURCE_DIR}/dist/installer/mac/Qt Profiler.entitlements")

  # Copies the icon into qtprofiler.app/Contents/Resources in the build tree.
  set(qtprofiler_icon "${CMAKE_CURRENT_SOURCE_DIR}/macos/qtprofiler.icns")
  target_sources(qtprofiler PRIVATE "${qtprofiler_icon}")
  set_source_files_properties("${qtprofiler_icon}" PROPERTIES
    MACOSX_PACKAGE_LOCATION "Resources"
  )

  # Copy translations to build dir. Themes are compiled into the app with
  # qt_add_resources below
  qtc_output_binary_dir(_output_binary_dir)
  qtc_copy_to_builddir(copy_qtprofiler_resources
    DIRECTORIES "${_output_binary_dir}/${IDE_DATA_PATH}/translations"
    DESTINATION "${qtprofiler_bundle_name}.app/Contents/Resources/translations"
  )
  # The generated translations must exist in the build tree before we copy them.
  if (TARGET generate_qm_files)
    add_dependencies(copy_qtprofiler_resources generate_qm_files)
  endif()
endif()

qtc_add_resources(qtprofiler "schema"
  PREFIX "/qtprofiler"
  FILES
    schema/qtprofilerapi.json.schema
)

# Compile the editor themes (and every file they include) straight into the
# binary, so the application loads them from ":/qtprofiler/themes" instead of a
# themes directory on disk. The includes are resolved relative to the theme
# file, so they must live next to it under the same resource prefix.
if (TARGET qtprofiler)
  set(qtprofiler_themes_dir "${PROJECT_SOURCE_DIR}/share/qtcreator/themes")
  qt_add_resources(qtprofiler "themes"
    PREFIX "/qtprofiler/themes"
    BASE "${qtprofiler_themes_dir}"
    FILES
      "${qtprofiler_themes_dir}/dark-2024.creatortheme"
      "${qtprofiler_themes_dir}/light-2024.creatortheme"
      "${qtprofiler_themes_dir}/dark.figmatokens"
      "${qtprofiler_themes_dir}/light.figmatokens"
      "${qtprofiler_themes_dir}/primitive-colors.inc"
      "${qtprofiler_themes_dir}/2024.tokenmapping"
      "${qtprofiler_themes_dir}/ds.tokenmapping"
      "${qtprofiler_themes_dir}/qmldesigner-dark.inc"
      "${qtprofiler_themes_dir}/qmldesigner-light.inc"
  )
endif()

# add_qtc_executable() builds on plain add_executable(), so the executable
# finalization that qt_add_executable() defers never runs. Run it explicitly: on
# Emscripten it generates qtprofiler.html from Qt's shell template, copies
# qtloader.js/qtlogo.svg, links embind (the QPA plugin uses emscripten::val), and
# sets the MODULARIZE/EXPORT_NAME/EXPORTED_RUNTIME_METHODS and memory link options
# the generated loader depends on. Only done for WebAssembly, where the app is
# unusable without it; the desktop builds have never been finalized either.
if (EMSCRIPTEN AND TARGET qtprofiler)
  # A Qt for WebAssembly without thread support parses a trace on the main thread (see
  # Utils::asyncRun), where Utils::asyncYield() has to suspend mid-parse and give the
  # browser its turn so that the window stays alive. That needs JSPI or Asyncify; a Qt
  # configured with JSPI carries the linker options for it itself, so only fall back to
  # Asyncify, whose default stack holds far less than the parser call stacks it has to
  # save here. With thread support none of this applies: the trace is parsed on a thread
  # and asyncYield() compiles to nothing.
  if (NOT QT_FEATURE_wasm_jspi AND NOT QT_FEATURE_thread)
    target_link_options(qtprofiler PRIVATE -sASYNCIFY -sASYNCIFY_STACK_SIZE=1048576)
  endif()
  # Qt's platform plugin bundles DejaVu Sans and DejaVu Sans Mono in full, about
  # 1 MB of the module, most of it scripts a trace viewer never shows. A resource
  # defined here under the plugin's own name and paths satisfies the plugin's
  # reference to it, so the linker never pulls Qt's copy out of the plugin archive.
  # The subset keeps Latin, Greek and Cyrillic, which can turn up in a trace's
  # strings, and the punctuation and symbol blocks. Hinting stays, so every glyph
  # that is kept renders as before.
  set(QTPROFILER_WASM_FONT_SOURCE "" CACHE PATH
      "Directory with the DejaVuSans.ttf and DejaVuSansMono.ttf to subset, e.g. qtbase/src/3rdparty/wasm")
  if (QTPROFILER_WASM_FONT_SOURCE)
    find_program(PYFTSUBSET_EXECUTABLE pyftsubset)
    if (NOT PYFTSUBSET_EXECUTABLE)
      message(WARNING "pyftsubset (fonttools) not found: qtprofiler keeps Qt's full fonts.")
    else()
      set(unicodes "U+0000-036F,U+0370-03FF,U+0400-052F,U+1E00-1EFF,U+2000-209F,U+20A0-20CF,U+2100-218F,U+2190-23FF,U+2500-27BF,U+FFFD")
      set(subset_dir "${CMAKE_CURRENT_BINARY_DIR}/wasmfonts")
      file(MAKE_DIRECTORY "${subset_dir}")
      set(subset_files "")
      foreach(font DejaVuSans DejaVuSansMono)
        add_custom_command(OUTPUT "${subset_dir}/${font}.ttf"
          COMMAND "${PYFTSUBSET_EXECUTABLE}" "${QTPROFILER_WASM_FONT_SOURCE}/${font}.ttf"
                  "--unicodes=${unicodes}" "--layout-features=*" "--name-IDs=*"
                  "--name-languages=*" --notdef-outline
                  "--output-file=${subset_dir}/${font}.ttf"
          DEPENDS "${QTPROFILER_WASM_FONT_SOURCE}/${font}.ttf"
          VERBATIM)
        list(APPEND subset_files "${subset_dir}/${font}.ttf")
      endforeach()
      qt_add_resources(qtprofiler wasmfonts
        PREFIX "/fonts"
        BASE "${subset_dir}"
        FILES ${subset_files}
      )
    endif()
  endif()
  qt_finalize_target(qtprofiler)
endif()

# The call-stack sampler uses task_for_pid(), which requires the binary to carry
# the debugger entitlement. Re-sign (ad-hoc) after each build so the freshly
# linked binary keeps it. Without this the sampler fails at attach time.
if (APPLE AND TARGET qtprofiler)
  add_custom_command(TARGET qtprofiler POST_BUILD
    COMMAND codesign --sign - --force
            --entitlements "${QtCreator_SOURCE_DIR}/dist/installer/mac/Qt Profiler.entitlements"
            "$<TARGET_BUNDLE_DIR:qtprofiler>"
    VERBATIM
    COMMENT "Codesigning qtprofiler with the debugger entitlement"
  )
endif()

if (NOT TARGET qtprofiler OR NOT BUILD_EXECUTABLE_QTPROFILER_STANDALONE)
  return()
endif()

create_standalone_install_component(qtprofiler
  TARGET qtprofiler
  PLUGINS
    platforminputcontexts
    platforms
    platformthemes
    styles
    wayland-decoration-client
    wayland-graphics-integration-client
    wayland-shell-integration
    xcbglintegrations
  IMPORTS
    Qt
    QtCore
    QtNetwork
    QtQml
    QtWayland
  RESOURCES
    translations
)
