load(moc)
load(resources)

defineReplace(getTargetType) {
    equals(TEMPLATE, "app"):return("executable")
    equals(TEMPLATE, "lib") {
       CONFIG(static): return("static_library")
       return("shared_library")
  }
  return("none")
}

defineReplace(filter_flag_values) {
    value_to_check = $$1
    if (macos|ios):equals(value_to_check, "$(EXPORT_ARCH_ARGS)") {
        # EXPORT_ARCH_ARGS comes from qtbase/mkspecs/features/mac/default_post.prf which is a way
        # to figure out the architectures to pass to the compiler at Makefile time. Because this
        # variable expansion is not supported by GN, we filter it out. GN takes care of assigning
        # the architecture itself.
        return("")
    }
    if (ios) {
        equals(value_to_check, "$(EXPORT_QMAKE_XARCH_LFLAGS)"): return("")
        equals(value_to_check, "$(EXPORT_QMAKE_XARCH_CFLAGS)"): return("")
    }

    return($$value_to_check)
}

isEmpty(GN_FILE): GN_FILE = $$system_path($$_PRO_FILE_PWD_/BUILD.gn)
isEmpty(GN_RUN_BINARY_SCRIPT): GN_RUN_BINARY_SCRIPT = "//build/gn_run_binary.py"
isEmpty(GN_FIND_MOCABLES_SCRIPT): GN_FIND_MOCABLES_SCRIPT = "//build/gn_find_mocables.py"

# MOC SETUP

GN_CONTENTS += "moc_source_h_files = exec_script(\"$$GN_FIND_MOCABLES_SCRIPT\","
GN_CONTENTS += "  ["
for (headerfile, HEADERS): GN_CONTENTS += "    \"$$GN_SRC_DIR/$$headerfile\","
GN_CONTENTS += "  ], \"list lines\", [\"$$system_path($$_PRO_FILE_)\"]"\
               ")"
GN_CONTENTS += "moc_source_cpp_files = exec_script(\"$$GN_FIND_MOCABLES_SCRIPT\","
GN_CONTENTS += "  ["
for (sourcefile, SOURCES): GN_CONTENTS += "    \"$$GN_SRC_DIR/$$sourcefile\","
GN_CONTENTS += "  ], \"list lines\", [\"$$system_path($$_PRO_FILE_)\"]"\
               ")"

DEFINES_LIST = $$join(DEFINES, " -D", "-D")
INCLUDE_LIST = $$join(INCLUDEPATH, " -I", "-I")

# we don't generate a moc_predef file yet.
MOC_PREDEF_FILE =
MOC_COMMAND = $$clean_path($$mocCmdBase())
MOC_COMMAND = $$replace(MOC_COMMAND, $$re_escape("$(DEFINES)"), $$DEFINES_LIST)
MOC_COMMAND = $$replace(MOC_COMMAND, $$re_escape("$(INCPATH)"), $$INCLUDE_LIST)
MOC_COMMAND = $$eval($$list($$MOC_COMMAND))

GN_CONTENTS += "if (moc_source_h_files != []) {"
GN_CONTENTS += "  action_foreach(\"generate_h_mocs\") {"\
               "    script = \"$$GN_RUN_BINARY_SCRIPT\""
GN_CONTENTS += "    sources =  moc_source_h_files" \
               "    outputs = [ \"$target_gen_dir/.moc/moc_{{source_name_part}}.cpp\" ]"
GN_CONTENTS += "    inputs = [ \"$$system_path($$_PRO_FILE_)\" ]" \
               "    args = ["
for(token, MOC_COMMAND): GN_CONTENTS += "      \"$$replace(token,\",\\\")\","
GN_CONTENTS += "      \"{{source}}\"," \
               "      \"-o\"," \
               "      rebase_path(\"$target_gen_dir/.moc/moc_{{source_name_part}}.cpp\")"\
               "    ]"
GN_CONTENTS += "  }"
GN_CONTENTS += "}"
GN_CONTENTS += "if (moc_source_cpp_files != []) {"
GN_CONTENTS += "  action_foreach(\"generate_cpp_mocs\") {"\
               "    script = \"$$GN_RUN_BINARY_SCRIPT\""
GN_CONTENTS += "    sources =  moc_source_cpp_files" \
               "    outputs = [ \"$target_gen_dir/.moc/{{source_name_part}}.moc\" ]"
GN_CONTENTS += "    inputs = [ \"$$system_path($$_PRO_FILE_)\" ]" \
               "    args = ["
for(token, MOC_COMMAND): GN_CONTENTS += "      \"$$replace(token,\",\\\")\","
GN_CONTENTS += "      \"{{source}}\"," \
               "      \"-o\"," \
               "      rebase_path(\"$target_gen_dir/.moc/{{source_name_part}}.moc\")"\
               "    ]"
GN_CONTENTS += "  }"
GN_CONTENTS += "}"

# RESOURCES SETUP

CLEAN_QMAKE_RCC = $$clean_path($$QMAKE_RCC)

!isEmpty(RESOURCES) {
    GN_CONTENTS += "action_foreach(\"generate_resources\") {"\
                "  script = \"$$GN_RUN_BINARY_SCRIPT\""
    GN_CONTENTS += "  sources = ["
    for (sourcefile, RESOURCES): GN_CONTENTS += "    \"$$GN_SRC_DIR/$$sourcefile\","
    GN_CONTENTS += "  ]" \
                "  outputs = [ \"$target_gen_dir/.rcc/qrc_{{source_name_part}}.cpp\" ]"
    GN_CONTENTS += "  inputs = [ \"$$system_path($$_PRO_FILE_)\" ]" \
                "  args = [" \
                "    \"$$replace(CLEAN_QMAKE_RCC,\",\\\")\","
    for(resource_flag, $$QMAKE_RESOURCE_FLAGS): GN_CONTENTS += "    \"$$resource_flag\""
    GN_CONTENTS += "    \"-name\"," \
                "    \"{{source_name_part}}\"," \
                "    \"{{source}}\"," \
                "    \"-o\"," \
                "    rebase_path(\"$target_gen_dir/.rcc/qrc_{{source_name_part}}.cpp\")"\
                "   ]"
    GN_CONTENTS += "}"
}

# CONFIG SETUP

GN_CONTENTS += "config(\"$${TARGET}_config\") {"
!isEmpty(QMAKE_CFLAGS) {
    GN_CONTENTS += "  cflags = ["
    for(flag, QMAKE_CFLAGS): GN_CONTENTS += "    \"$$filter_flag_values($$flag)\","
    GN_CONTENTS += "  ]"
}

!isEmpty(QMAKE_FRAMEWORKPATH) {
    GN_CONTENTS += "  cflags += ["
    for(path, QMAKE_FRAMEWORKPATH): GN_CONTENTS += "    \"-F$$path\","
    GN_CONTENTS += "  ]"
}

# Stop the barrage of unused variables warnings.
gcc|clang|clang_cl {
    QMAKE_CXXFLAGS += "-Wno-unused-parameter"
    QMAKE_CXXFLAGS += "-Wno-unused-variable"
} else:msvc {
    QMAKE_CXXFLAGS += /wd4100 /wd4101
}

# Chromium activates this, but we need it off to be able to compile QFlags
clang_cl {
    QMAKE_CXXFLAGS += "-fno-complete-member-pointers"
}

!isEmpty(QMAKE_CXXFLAGS) {
    GN_CONTENTS += "  cflags_cc = ["
    for(flag, QMAKE_CXXFLAGS): GN_CONTENTS += "    \"$$filter_flag_values($$flag)\","
    GN_CONTENTS += "  ]"
}

GN_CONTENTS += "  defines = ["
# Remove single quotes around function macro defines, so that GN doesn't escape them, thus breaking
# the macro.
# Also add a layer of escaping for double quotes.
for (define, DEFINES): {
  define = $$replace(define,\",\\\")
  define = $$replace(define,\',)
  GN_CONTENTS += "    \"$$define\","
}
GN_CONTENTS += "  ]"

GN_CONTENTS += "  include_dirs = ["
for (path, INCLUDEPATH): GN_CONTENTS += "    \"$$path\","
GN_CONTENTS += "    rebase_path(\"$target_gen_dir/.moc/\"),"
GN_CONTENTS += "    \"$$QMAKESPEC\""
GN_CONTENTS += "  ]"

GN_CONTENTS += "  ldflags = ["
for (flag, QMAKE_LFLAGS): GN_CONTENTS += "    \"$$filter_flag_values($$flag)\","
for (flag, GN_FLAGS): GN_CONTENTS += "    \"$$flag\","
!isEmpty(QMAKE_RPATHDIR) {
    for (rpath, QMAKE_RPATHDIR) {
        unix:!macos: GN_CONTENTS += "    \"-Wl,-rpath=$${rpath}\","
    }
}
!isEmpty(QMAKE_RPATHLINKDIR): GN_CONTENTS += "    \"-Wl,-rpath-link=$${QMAKE_RPATHLINKDIR}\","
GN_CONTENTS += "  ]"

GN_CONTENTS += "  lib_dirs = ["
lib_dirs = $$find(LIBS, ^-L.*)
lib_dirs = $$unique(lib_dirs)
for (lib_dir, lib_dirs): GN_CONTENTS += "    \"$$replace(lib_dir, -L, )\","
GN_CONTENTS += "  ]"

GN_CONTENTS += "}"

# TARGET SETUP

TARGET_TYPE = $$getTargetType()

GN_CONTENTS += "$${TARGET_TYPE}(\"$$TARGET\") {"
!isEmpty(GN_CREATE_PRI): GN_CONTENTS += "  create_pri_file = $$GN_CREATE_PRI"
!isEmpty(GN_IMPORTS) {
    for (imp, GN_IMPORTS): GN_CONTENTS += "  import(\"$$imp\")"
}

GN_CONTENTS += "  configs += [ \":$${TARGET}_config\" ]"
!isEmpty(GN_PRECOMPILED_HEADERS): GN_CONTENTS += "  configs += [ \"//build/config:precompiled_headers\" ]"

# Source files to compile
GN_CONTENTS += "  sources = ["
for (sourcefile, SOURCES): GN_CONTENTS += "    \"$$GN_SRC_DIR/$$sourcefile\","
for (headerfile, HEADERS): GN_CONTENTS += "    \"$$GN_SRC_DIR/$$headerfile\","
GN_CONTENTS += "  ]"

# Add Sources generated by rcc from qrc files.
!isEmpty(RESOURCES): GN_CONTENTS += "  sources += get_target_outputs(\":generate_resources\")"

GN_CONTENTS += "  if (!defined(libs)) {"\
               "    libs = []"\
               "  }"
GN_CONTENTS += "  libs += ["
for (lib, GN_LIBS): GN_CONTENTS += "    \"$$lib\","
libs = $$find(LIBS, ^-l.*)
libs = $$unique(libs)
for (lib, libs): GN_CONTENTS += "    \"$$replace(lib, -l, )\","
GN_CONTENTS += "  ]"

GN_CONTENTS += "  if (!defined(deps)) {"\
               "    deps = []"\
               "  }"

!isEmpty(RESOURCES) {
    GN_CONTENTS += "  deps += ["
    GN_CONTENTS += "      \":generate_resources\","
    GN_CONTENTS += "  ]"
}

# Remove the default no_rtti config for our own cpp files, thus leaving the decision
# to the compiler's defaults. This is consistent with how qtbase does it.
# Unless the user explicitly configured Qt with a different RTTI setting.
# Windows only for now, because macOS (and presumably Linux) does not support
# partial rtti info (e.g. rtti info present for derived class, but not base class), and the
# qtbase rtti feature affects only Windows.
win32 {
    GN_CONTENTS += "  configs -= [\"//build/config/compiler:no_rtti\"]"
    CONFIG(rtti_off): GN_CONTENTS += "  configs += [\"//build/config/compiler:no_rtti\"]"
    CONFIG(rtti): GN_CONTENTS += "  configs += [\"//build/config/compiler:rtti\"]"
}
gcc:!qtConfig(reduce_exports) {
    GN_CONTENTS += "  configs -= [\"//build/config/gcc:symbol_visibility_hidden\"]"
}

GN_CONTENTS += "  if (moc_source_h_files != []) {"
GN_CONTENTS += "    deps += ["
GN_CONTENTS += "        \":generate_h_mocs\","
GN_CONTENTS += "    ]"
# Add moc output files to compile
GN_CONTENTS += "    sources += get_target_outputs(\":generate_h_mocs\")"
GN_CONTENTS += "  }"
GN_CONTENTS += "  if (moc_source_cpp_files != []) {"
GN_CONTENTS += "    deps += ["
GN_CONTENTS += "        \":generate_cpp_mocs\","
GN_CONTENTS += "    ]"
GN_CONTENTS += "  }"
GN_CONTENTS += "}"
!isEmpty(GN_CORE_INCLUDE_DIRS) {
   GN_CONTENTS += "  if (!defined(core_include_dirs)) {"\
                  "    core_include_dirs = []"\
                  "  }"
   GN_CONTENTS += "core_include_dirs += ["
   for (inc, GN_CORE_INCLUDE_DIRS): GN_CONTENTS += "    \"$$inc\","
   GN_CONTENTS += "]"
}

!isEmpty(GN_INCLUDES) {
    for (inc, GN_INCLUDES): GN_CONTENTS += $$cat($$inc,lines)
}

build_pass|!debug_and_release: write_file($$GN_FILE, GN_CONTENTS)

# The generated Makefile shouldn't build anything by itself, just re-run qmake if necessary
TEMPLATE = aux
SOURCES =
HEADERS =
RESOURCES =

QMAKE_DISTCLEAN += $$GN_FILE
