#
# This file is used to specify Reko intra-project targets
# It works around various MSBuild limitations, such as
# - weak handling of generated files, or files generated by other commands (run project X to generate file Y)
# - weak tracking of generated files (run this target only if file Y changed)
# - weak intra-project target build order (we need project A to generate file X in project B)
#
# Particularly, using MSBuild's <Exec> element within a .csproj file,
# **when this project is referenced by other projects or a .sln file**,
# seems to cause MSBuild to think the project is outdated (maybe because <Exec> is unconditional).
#
# This "outdated" bit is propagated to all dependent projects, which will be rebuilt as a result.
# This causes a big part of the solution to be rebuilt every time the project is built or ran, even tho nothing was changed
#
# The targets created in this file are invoked through a proxy project, `BuildTargets.csproj`, which is *NOT* part of Reko-decompiler.sln
# `BuildTargets.csproj` is also *NOT* referenced by any other project,
# but it's instead invoked directly with a <MSBuild> element placed in the required .csproj
#

if(NOT CMAKE_BUILD_TYPE)
	set(CMAKE_BUILD_TYPE "Debug")
endif()

# The path to the Reko's "src" directory, used for relative path
set(REKO_SRC ${CMAKE_CURRENT_LIST_DIR})
set(REKO_VERSION "0.11.4")

set(artifacts_dir ${REKO_SRC}/../bin)
file(MAKE_DIRECTORY ${artifacts_dir})

#
# This function obtains the output path of a given csproj
# The logic works like this
# `PROJECT_NAME` specifies both the name of the folder AND the filename of the .csproj file
# so given 'a' the resulting project file will be 'a/a.csproj'
# 
# If the project is part of another directory tree,
# you can specify a path prefix by using `PROJECT_SUBDIR`, which will be prepended to the path
#
# The artifacts are assumed to be produced in "bin/<platform>/<configuration>/<framework>"
# if `PREFER_INTERMEDIATE`, the top level directory used will be "obj" instead of "bin"
# -  <platform> is obtained from the *global* variable `REKO_PLATFORM`
# -  <configuration> is obtained from the *global* variable `CMAKE_BUILD_TYPE`
# -  <framework> is specified by the parameter `FRAMEWORK`
#
# If the assembly targets "AnyCPU", and thus has no platform, you can pass `ANYCPU` to skip the platform logic
# 
# The assembly's filename is constructed like this
# <prefix><project_name><suffix>
# example: <Reko.Arch.><X86><.dll>
# -  <prefix> is specified by `OUTPUT_PREFIX` -> 'Reko.Arch.'
# -  <project_name> is specified by `PROJECT_NAME`
# -  <suffix> is controlled by `LIB` (which adds '.dll') or `EXE` (which adds '.exe' only on Windows). 
#
# The final path is stored in the output variable specified by `RESULT`
function(csproj_output_path)
	cmake_parse_arguments(asm "LIB;EXE;ANYCPU;PREFER_INTERMEDIATE" "PROJECT_SUBDIR;PROJECT_NAME;FRAMEWORK;OUTPUT_PREFIX;OUTPUT_SUFFIX;RESULT" "" ${ARGN})

	set(asm_basedir ${REKO_SRC})
	if(asm_PROJECT_SUBDIR)
		string(APPEND asm_basedir "/${asm_PROJECT_SUBDIR}")
	endif()

	if(NOT asm_FRAMEWORK)
		if(asm_LIB)
			set(asm_FRAMEWORK ${REKO_LIB_FRAMEWORK})
		elseif(asm_EXE)
			set(asm_FRAMEWORK ${REKO_EXE_FRAMEWORK})
		else()
			message(FATAL_ERROR "Neither FRAMEWORK nor LIB/EXE specified")
		endif()
	endif()

	if(NOT asm_OUTPUT_SUFFIX)
		if(asm_LIB)
			set(asm_OUTPUT_SUFFIX ".dll")
		elseif(asm_EXE)
			if(WIN32)
				set(asm_OUTPUT_SUFFIX ".exe")
			else()
				set(asm_OUTPUT_SUFFIX "")
			endif()
		endif()
	endif()

	set(asm_filename ${asm_OUTPUT_PREFIX}${asm_PROJECT_NAME}${asm_OUTPUT_SUFFIX})

	set(asm_bin_path ${asm_basedir}/${asm_PROJECT_NAME}/bin)
	set(asm_obj_path ${asm_basedir}/${asm_PROJECT_NAME}/obj)

	set(asm_binpath_relative "")
	if(NOT asm_ANYCPU)
		set(asm_binpath_relative ${REKO_PLATFORM})
	endif()

	string(APPEND asm_binpath_relative ${CMAKE_BUILD_TYPE}/${asm_FRAMEWORK}/${asm_filename})

	if(asm_PREFER_INTERMEDIATE)
		set(${asm_RESULT} ${asm_obj_path}/${asm_binpath_relative} PARENT_SCOPE)
	else()
		set(${asm_RESULT} ${asm_bin_path}/${asm_binpath_relative} PARENT_SCOPE)
	endif()
endfunction()

#
# This function creates a new target that will copy (at build time)
# the file specified by `SRC_PATH` to a destination specified by `DEST_PATH`
# the target name is generated automatically from `SRC_PATH`,
# and stored in the variable name indicated by `OUT_TARGET_NAME`
#
function(add_copy_target)
	cmake_parse_arguments(copy "" "SRC_PATH;DEST_PATH;OUT_TARGET_NAME" "" ${ARGN})

	string(MD5 copy_TARGET_NAME "${copy_SRC_PATH}_${copy_DEST_PATH}")
	set(${copy_OUT_TARGET_NAME} ${copy_TARGET_NAME} PARENT_SCOPE)

	if(TARGET ${copy_TARGET_NAME})
		return()
	endif()

	get_filename_component(dest_dir ${copy_SRC_PATH} DIRECTORY)

	# create a command that will copy this file
	add_custom_command(
		OUTPUT ${copy_DEST_PATH}
		COMMENT "Copying ${copy_SRC_PATH} -> ${copy_DEST_PATH}"
		COMMAND ${CMAKE_COMMAND} -E make_directory ${dest_dir}
		COMMAND ${CMAKE_COMMAND} -E copy ${copy_SRC_PATH} ${copy_DEST_PATH}
	)

	# create a target that will run the copy command if the destination file is out of date
	add_custom_target(
		${copy_TARGET_NAME}
		COMMENT "Copying ${copy_SRC_PATH} -> ${copy_DEST_PATH}"
		DEPENDS ${copy_DEST_PATH}
	)
endfunction()

#
# This function creates a new target that will run c2xml when invoked
# The arguments control both the invocation parameters as well as the requirements that must be met before c2xml can be ran
## INVOCATION:
# `REKO_ARCH` is mapped to the '-a' argument
# `REKO_ENV` is mapped to the '-e' argument
# `DIALECT` is mapped to the '-d' argument
# `HEADER` is mapped to the input filename (the .xml file passed to c2xml)
#
## REQUIREMENTS:
# `REQUIRED_ARCHITECTURES` is tne name of Reko.Arch projects that must be built as requirements (e.g. 'X86')
# `REQUIRED_ENVIRONMENTS` is the name of Reko.Environments proejcts that must be built as requirements (e.g. 'Windows')
#
## CMake:
# `OUTPUT` indicates the .h file that will be produced by c2xml (so it can be tracked)
# `TARGET_NAME` specifies the name to assign to the final target
#
function(add_c2xml_target)
	cmake_parse_arguments(c2xml "" "REKO_ARCH;REKO_ENV;DIALECT;OUTPUT;TARGET_NAME;HEADER" "REQUIRED_ARCHITECTURES;REQUIRED_ENVIRONMENTS" ${ARGN})

	csproj_output_path(
		EXE ANYCPU
		PROJECT_SUBDIR "tools"
		PROJECT_NAME "c2xml"
		RESULT c2xml_exe
	)

	get_filename_component(c2xml_dir "${c2xml_exe}" DIRECTORY)

	## Workaround for 'You must install .NET to run this application.'
	if(APPLE)
		set(c2xml_exe dotnet ${c2xml_exe}.dll)
	endif()

	add_custom_command(
		OUTPUT ${c2xml_OUTPUT}
			COMMAND ${c2xml_exe}
				-a "${c2xml_REKO_ARCH}"
				-e "${c2xml_REKO_ENV}"
				-d "${c2xml_DIALECT}"
				${c2xml_HEADER}
				${c2xml_OUTPUT}
	)

	add_custom_target(
		${c2xml_TARGET_NAME}
		COMMENT "c2xml ${c2xml_HEADER} -> ${c2xml_OUTPUT}"
		DEPENDS ${c2xml_OUTPUT}
	)

	## start off with reko.config
	set(file_list "${REKO_SRC}/Drivers/reko.config")

	## collect arch dlls
	foreach(arch ${c2xml_REQUIRED_ARCHITECTURES})
		csproj_output_path(
			LIB ANYCPU
			PROJECT_SUBDIR "Arch"
			PROJECT_NAME "${arch}"
			OUTPUT_PREFIX "Reko.Arch."
			RESULT arch_dll
			PREFER_INTERMEDIATE
		)
		message(DEBUG "[arch] ${arch} => ${arch_dll}")
		
		list(APPEND file_list ${arch_dll})
	endforeach()

	## collect env dlls
	foreach(env ${c2xml_REQUIRED_ENVIRONMENTS})
		csproj_output_path(
			LIB ANYCPU
			PROJECT_SUBDIR "Environments"
			PROJECT_NAME "${env}"
			OUTPUT_PREFIX "Reko.Environments."
			RESULT env_dll
			PREFER_INTERMEDIATE
		)
		message(DEBUG "[env] ${env} => ${env_dll}")
		list(APPEND file_list ${env_dll})
	endforeach()

	foreach(src_path ${file_list})
		add_c2xml_copy_target(
			SRC_PATH ${src_path}
			DEST_DIR ${c2xml_dir}
			MAIN_TARGET ${c2xml_TARGET_NAME}
		)
	endforeach()
endfunction()

function(add_c2xml_copy_target)
	cmake_parse_arguments(c2xml "" "SRC_PATH;DEST_DIR;MAIN_TARGET" "" ${ARGN})

	# use the filename without extension as the copy target name
	# get_filename_component(filename_we "${c2xml_SRC_PATH}" NAME_WE)
	get_filename_component(filename "${c2xml_SRC_PATH}" NAME)

	set(dest_path ${c2xml_DEST_DIR}/${filename})

	add_copy_target(
		SRC_PATH ${c2xml_SRC_PATH}
		DEST_PATH ${dest_path}
		OUT_TARGET_NAME copy_target_name
	)

	# we need to copy the assemblies before we can run c2xml
	add_dependencies(${c2xml_MAIN_TARGET} ${copy_target_name})
endfunction()

#
# This function is used to simplify the generation of Windows metadata
# It will create a new target for the given `header`, and append it to `main_target`
# `main_target` specifies the name of the top-level target (that will build ALL Windows metadata)
#
function(add_c2xml_target_windows main_target header)
	string(REPLACE "/" "_" target ${header})
	set(target_name "gen_c2xml_windows_${target}")

	add_c2xml_target(
		REKO_ARCH "x86-protected-32"
		REKO_ENV "win32"
		REQUIRED_ARCHITECTURES "X86"
		REQUIRED_ENVIRONMENTS "Windows"
		DIALECT "msvc"
		TARGET_NAME "${target_name}"
		HEADER ${REKO_SRC}/Environments/Windows/${header}.inc
		OUTPUT ${REKO_SRC}/Environments/Windows/${header}.xml
	)
	add_dependencies(${main_target} ${target_name})
endfunction()


function(add_c2xml_target_win16 main_target header)
	string(REPLACE "/" "_" target ${header})
	set(target_name "gen_c2xml_windows_${target}")

	add_c2xml_target(
		REKO_ARCH "x86-protected-16"
		REKO_ENV "win16"
		REQUIRED_ARCHITECTURES "X86"
		REQUIRED_ENVIRONMENTS "Windows"
		DIALECT "msvc"
		TARGET_NAME "${target_name}"
		HEADER ${REKO_SRC}/Environments/Windows/${header}.inc
		OUTPUT ${REKO_SRC}/Environments/Windows/${header}.xml
	)
	add_dependencies(${main_target} ${target_name})
endfunction()

#
# This function is used to simplify the generation of OS2 metadata
# It will create a new target for the given `header`, and append it to `main_target`
# `main_target` specifies the name of the top-level target (that will build ALL OS2 metadata)
#
function(add_c2xml_target_os2 main_target header)
	string(REPLACE "/" "_" target ${header})
	set(target_name "gen_c2xml_windows_${target}")

	add_c2xml_target(
		REKO_ARCH "x86-protected-32"
		REKO_ENV "os2-16"
		REQUIRED_ARCHITECTURES "X86"
		REQUIRED_ENVIRONMENTS "OS2"
		DIALECT "msvc"
		TARGET_NAME "${target_name}"
		HEADER ${REKO_SRC}/Environments/OS2/${header}.inc
		OUTPUT ${REKO_SRC}/Environments/OS2/${header}.xml
	)
	add_dependencies(${main_target} ${target_name})
endfunction()

#
# This function is used to simplify the generation of SysV metadata
# It will create a new target for the given `header`, and append it to `main_target`
# `main_target` specifies the name of the top-level target (that will build ALL SysV metadata)
#
function(add_c2xml_target_sysv main_target header)
	string(REPLACE "/" "_" target ${header})
	set(target_name "gen_c2xml_sysv_${target}")

	add_c2xml_target(
		REKO_ARCH "x86-protected-32"
		REKO_ENV "elf-neutral"
		REQUIRED_ARCHITECTURES "X86"
		REQUIRED_ENVIRONMENTS "SysV"
		DIALECT "gcc"
		TARGET_NAME "${target_name}"
		HEADER ${REKO_SRC}/Environments/SysV/${header}.inc
		OUTPUT ${REKO_SRC}/Environments/SysV/${header}.xml
	)
	add_dependencies(${main_target} ${target_name})
endfunction()


set(GUI_BASEDIR ${REKO_SRC}/Gui)

if("${TARGET}" STREQUAL "run_hdrgen")
	# 
	# we need to obtain the path where Reko.Core.dll will be built, 
	# since it's a dependency to 'hdrgen'
	#
	csproj_output_path(
		LIB ANYCPU
		PROJECT_NAME "Core"
		OUTPUT_PREFIX "Reko."
		RESULT reko_core_dll
	)

	#
	# Create a new target to generate NativeProxy header files
	#
	RUN_DOTNET(${REKO_SRC}/tools/hdrgen/hdrgen.csproj
		NO_RESTORE
		NO_CLEAN
		CONFIG ${CMAKE_BUILD_TYPE}
		# PLATFORM ${REKO_PLATFORM}
		ARGUMENTS
			${reko_core_dll}
			${REKO_SRC}/Native/include/reko.h
		SOURCES
			${reko_core_dll}
		OUTPUT
			${REKO_SRC}/Native/include/reko.h
		TARGET_NAME "run_hdrgen"
	)
elseif("${TARGET}" STREQUAL "gen_c2xml_windows")
	add_custom_target(gen_c2xml_windows)
	add_c2xml_target_windows(gen_c2xml_windows msvcrt)
	add_c2xml_target_windows(gen_c2xml_windows ntoskrnl)
	add_c2xml_target_win16(gen_c2xml_windows win16c)
elseif("${TARGET}" STREQUAL "gen_c2xml_os2")
	add_custom_target(gen_c2xml_os2)
	add_c2xml_target_os2(gen_c2xml_os2 os2-16)
	add_c2xml_target_os2(gen_c2xml_os2 16/fsu)
	add_c2xml_target_os2(gen_c2xml_os2 16/fsh)
	add_c2xml_target_os2(gen_c2xml_os2 16/fsd)
elseif("${TARGET}" STREQUAL "gen_c2xml_sysv")
	add_custom_target(gen_c2xml_sysv)
	add_c2xml_target_sysv(gen_c2xml_sysv lp32)
	add_c2xml_target_sysv(gen_c2xml_sysv lp64)
	add_c2xml_target_sysv(gen_c2xml_sysv libc.so)
	add_c2xml_target_sysv(gen_c2xml_sysv Xlib)
	add_c2xml_target_sysv(gen_c2xml_sysv opengl)
elseif("${TARGET}" STREQUAL "nativeproxy_clean")
	#
	# Create a new target to clean NativeProxy
	#
	add_custom_target(nativeproxy_clean
		COMMENT "Cleaning NativeProxy..."
		WORKING_DIRECTORY ${REKO_SRC}/Native
		COMMAND ${CMAKE_COMMAND}
			-DREKO_SRC=${REKO_SRC}
			-DREKO_ROOT=${REKO_SRC}/../
			-DREKO_PLATFORM=${REKO_PLATFORM}
			-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
			-DACTION=clean
			-P ${REKO_SRC}/Native/reko.cmake
	)
elseif("${TARGET}" STREQUAL "nativeproxy_build")
	#
	# Create a new target to build NativeProxy
	#
	add_custom_target(nativeproxy_build
		COMMENT "Building NativeProxy ..."
		WORKING_DIRECTORY ${REKO_SRC}/Native
		COMMAND ${CMAKE_COMMAND}
			-DIS_MSYS=${IS_MSYS}
			-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
			-DREKO_SRC=${REKO_SRC}
			-DREKO_ROOT=${REKO_SRC}/../
			-DREKO_PLATFORM=${REKO_PLATFORM}
			-DREKO_COMPILER=${REKO_COMPILER}
			-P ${REKO_SRC}/Native/reko.cmake
	)
elseif("${TARGET}" STREQUAL "git_hash")
	if(NOT GIT_HASH_OUTPUT)
		message(FATAL_ERROR "Variable GIT_HASH_OUTPUT is required")
	endif()
	#
	# Update the git hash AssemblyData for Reko.Core
	#
	include(${CMAKE_SOURCE_DIR}/cmake/CheckGit.cmake)
	CheckGitVersion(
		SCRIPT_FILE ${CMAKE_SOURCE_DIR}/cmake/CheckGit.cmake
		CACHE_FILE ${CMAKE_BINARY_DIR}/git-state.txt
		TEMPLATE_FILE ${CMAKE_SOURCE_DIR}/cmake/AssemblyData.Extra.cs.in
		OUTPUT_FILE ${GIT_HASH_OUTPUT}
		REPO_DIR ${REKO_SRC}
	)
	add_custom_target(git_hash)
	add_dependencies(git_hash AlwaysCheckGit)
elseif("${TARGET}" STREQUAL "build_solution")	
	#
	# Create a target to build the main solution
	#
	add_custom_target(build_solution
		COMMENT "Building solution..."
		WORKING_DIRECTORY ${REKO_SRC}
		COMMAND ${DOTNET_EXE} build
				${REKO_SRC}/Reko-decompiler.sln
				-c ${CMAKE_BUILD_TYPE} /p:Platform=${REKO_PLATFORM}
	)
elseif("${TARGET}" STREQUAL "run_unit_tests")
	TEST_DOTNET(${REKO_SRC}/UnitTests/UnitTests.csproj
		ARGUMENTS
			-c ${CMAKE_BUILD_TYPE}
			-p:Platform=${REKO_PLATFORM}
			--filter
			"(TestCategory!=FailedTests)&(TestCategory!=DotNetBug)&(TestCategory!=UserInterface)"
	)

	#
	# Create a target to run unit tests
	#
	add_custom_target(run_unit_tests
		COMMENT "Running Unit Tests..."
		WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
		COMMAND ${CMAKE_CTEST_COMMAND} -C ${CMAKE_BUILD_TYPE} -VV -R UnitTests
	)
elseif("${TARGET}" STREQUAL "run_regressions")
	#
	# Create a new target to run regression tests
	#
	RUN_DOTNET(${REKO_SRC}/tools/regressionTests/regressionTests.csproj
		NO_RESTORE
		NO_CLEAN
		CONFIG ${CMAKE_BUILD_TYPE}
		ARGUMENTS
			-c ${CMAKE_BUILD_TYPE}
			-p ${REKO_PLATFORM}
			--check-output
			${REKO_SRC} > ${CMAKE_BINARY_DIR}/regression.log
		OUTPUT
			# This file is expected to be produced by this target, but it never is
			# we use this trick so that this target is always marked outdated and will always run
			# however, we can also use this as a skip switch. the target won't run if this file exists
			${REKO_SRC}/../subjects/.skipregressions
		TARGET_NAME "run_regressions"
	)
elseif("${TARGET}" STREQUAL "create_runtime_nupkg")
	#
	# Create a new target to create the Runtime nupkg
	#
	add_custom_target(create_runtime_nupkg
		COMMENT "Creating Runtime nupkg..."
		COMMAND ${DOTNET_EXE} pack
			--no-build
			-c ${CMAKE_BUILD_TYPE}
			-p:Platform=${REKO_PLATFORM}
			-p:PackageVersion=${REKO_VERSION}
			${REKO_SRC}/Installers/Runtime/Runtime.csproj
	)
elseif("${TARGET}" STREQUAL "create_msi_wix")
	if(NOT DEFINED WIX_ROOT)
		message(FATAL_ERROR "Wix not found, cannot continue")
	endif()

	#
	# Create a new target to update the Wix spec
	#
	set(WINDRIVER_OUTDIR ${REKO_SRC}/Drivers/WindowsDecompiler/bin/${REKO_PLATFORM}/${CMAKE_BUILD_TYPE}/${REKO_WINFORMS_EXE_FRAMEWORK})
	RUN_DOTNET(${REKO_SRC}/tools/specGen/specGen.csproj
		NO_RESTORE
		NO_CLEAN
		CONFIG ${CMAKE_BUILD_TYPE}
		ARGUMENTS 
			wix
			${CMAKE_BUILD_TYPE}
			${REKO_PLATFORM}
			${REKO_SRC}/Installers/NuGetPackage/reko-files.xml
			${REKO_SRC}/Installers/WixInstaller/Components.wxi.template
			${REKO_SRC}/Installers/WixInstaller/Components.wxi
			${REKO_SRC}
		OUTPUT
			${REKO_SRC}/Installers/WixInstaller/.skipwixpecupdate
		TARGET_NAME "update_wix_spec"
	)

	find_program(CANDLE_EXECUTABLE candle
		PATHS ${WIX_ROOT}/bin
		REQUIRED
	)
	find_program(LIGHT_EXECUTABLE light
		PATHS ${WIX_ROOT}/bin
		REQUIRED
	)

	set(WIX_CANDLE_INPUT ${REKO_SRC}/Installers/WixInstaller/Product.wxs)
	set(WIX_CANDLE_OUTPUT ${CMAKE_BINARY_DIR}/wix/Reko.wixobj)
	set(WIX_LIGHT_OUTPUT ${CMAKE_BINARY_DIR}/wix/Reko-${REKO_VERSION}.msi)

	#
	# This command describes the process of getting 
	# WIX_CANDLE_OUTPUT (.wixobj)
	# from
	# WIX_CANDLE_INPUT (.wxs)
	#
	add_custom_command(
		OUTPUT ${WIX_CANDLE_OUTPUT}
		COMMAND
			${CANDLE_EXECUTABLE}
			-dSolutionDir=${REKO_SRC}/
			-dOUTDIR=${WINDRIVER_OUTDIR}
			-dEXEFILE=${WINDRIVER_OUTDIR}/WindowsDecompiler.exe
			-arch ${REKO_PLATFORM}
			-o ${WIX_CANDLE_OUTPUT}
			${WIX_CANDLE_INPUT}
		DEPENDS
			${WIX_CANDLE_INPUT} 
			${REKO_SRC}/Installers/WixInstaller/Component.wxi
	)
	# 
	# This target is linked with WIX_CANDLE_OUTPUT (.wixobj)
	# so that the corresponding command will run
	#
	add_custom_target("wix_compile_wxs"
		COMMENT "Wix: Compile .wxs to .wixobj"
		DEPENDS ${WIX_CANDLE_OUTPUT}
	)

	#
	# This command describes the process of getting 
	# WIX_LIGHT_OUTPUT (.msi)
	# from
	# WIX_CANDLE_OUTPUT (.wixobj)
	#
	add_custom_command(
		OUTPUT ${WIX_LIGHT_OUTPUT}
		COMMAND
			${LIGHT_EXECUTABLE}
			-ext WixUIExtension
			${WIX_CANDLE_OUTPUT}
			-o ${WIX_LIGHT_OUTPUT}
		DEPENDS ${WIX_CANDLE_OUTPUT}
	)
	# 
	# This target is linked with WIX_LIGHT_OUTPUT (.msi)
	# so that the corresponding command will run
	#
	add_custom_target("create_msi_wix"
		COMMENT "Wix: assemble .wixobj to .msi"
		DEPENDS ${WIX_LIGHT_OUTPUT}
	)

	# .msi depends on .wixobj
	add_dependencies(create_msi_wix wix_compile_wxs)
	# .wixobj depends on specGen
	add_dependencies(wix_compile_wxs update_wix_spec)
elseif("${TARGET}" STREQUAL "update_runtime_nuspec")
	#
	# Create a new target to update the Runtime nuspec
	#
	set(RUNTIME_OUTDIR ${REKO_SRC}/Installers/Runtime/bin/${REKO_PLATFORM}/${CMAKE_BUILD_TYPE}/${REKO_LIB_FRAMEWORK})
	RUN_DOTNET(${REKO_SRC}/tools/specGen/specGen.csproj
		NO_RESTORE
		NO_CLEAN
		CONFIG ${CMAKE_BUILD_TYPE}
		ARGUMENTS 
			nuget
			${CMAKE_BUILD_TYPE}
			${REKO_PLATFORM}
			${REKO_SRC}/Installers/NuGetPackage/reko-files.xml
			${REKO_SRC}/Installers/NuGetPackage/NuGetPackage.template
			${REKO_SRC}/Installers/Runtime/bin/Runtime-${REKO_PLATFORM}-${CMAKE_BUILD_TYPE}.nuspec
			${REKO_SRC}
		OUTPUT
			${REKO_SRC}/Installers/Runtime/.skipnuspecupdate
		TARGET_NAME "update_runtime_nuspec"
	)
elseif("${TARGET}" STREQUAL "create_release")
	include(FindSevenZip)

	if(DEFINED $ENV{APPVEYOR})
		string(SUBSTRING "$ENV{APPVEYOR_REPO_COMMIT}" 0 10 build_shorthash)
		set(build_version "$ENV{APPVEYOR_BUILD_VERSION}")
	elseif(DEFINED $ENV{GITHUB_WORKFLOW})
		string(SUBSTRING "$ENV{GITHUB_SHA}" 0 10 build_shorthash)
		set(build_version "${REKO_VERSION}.$ENV{GITHUB_RUN_NUMBER}")
	else()
		execute_process(
			COMMAND git rev-parse HEAD
			WORKING_DIRECTORY ${REKO_SRC}/../
			OUTPUT_VARIABLE head_sha
		)
		string(SUBSTRING "${head_sha}" 0 10 build_shorthash)
		set(build_version "${REKO_VERSION}")
	endif()

	add_custom_target(create_release)

	if(WIN32 AND NOT UNIX)
		add_custom_target(create_release_zip_windowsdecompiler
			COMMENT "Compressing WindowsDecompiler..."
			COMMAND ${SEVENZIP_BIN} a ${artifacts_dir}/WindowsDecompiler-${build_version}-${REKO_PLATFORM}-${build_shorthash}.zip
				${REKO_SRC}/Drivers/WindowsDecompiler/bin/${REKO_PLATFORM}/${CMAKE_BUILD_TYPE}/${REKO_WINFORMS_EXE_FRAMEWORK}/*
		)
		add_dependencies(create_release create_release_zip_windowsdecompiler)

		add_copy_target(
			SRC_PATH ${CMAKE_BINARY_DIR}/../create_msi_wix/wix/Reko-${REKO_VERSION}.msi
			DEST_PATH ${artifacts_dir}/Reko-${build_version}-${REKO_PLATFORM}-${build_shorthash}.msi
			OUT_TARGET_NAME copy_msi_target
		)
		add_dependencies(create_release ${copy_msi_target})
	endif()

	add_custom_target(create_release_zip_cmdline
		COMMENT "Compressing CmdLine..."
		COMMAND ${SEVENZIP_BIN} a ${artifacts_dir}/CmdLine-${build_version}-${build_shorthash}.zip
			${REKO_SRC}/Drivers/CmdLine/bin/${REKO_PLATFORM}/${CMAKE_BUILD_TYPE}/${REKO_EXE_FRAMEWORK}/*
	)
	add_dependencies(create_release create_release_zip_cmdline)

	add_copy_target(
		SRC_PATH ${REKO_SRC}/Installers/Runtime/bin/${REKO_PLATFORM}/${CMAKE_BUILD_TYPE}/Reko.Decompiler.Runtime.${REKO_VERSION}.nupkg
		DEST_PATH ${artifacts_dir}/Reko.Decompiler.Runtime.${build_version}-${REKO_PLATFORM}-${build_shorthash}.nupkg
		OUT_TARGET_NAME copy_runtime_nupkg_target
	)
	add_dependencies(create_release ${copy_runtime_nupkg_target})
elseif(NOT "${TARGET}" STREQUAL "")
	message(FATAL_ERROR "Unknown target ${TARGET}")
endif()
