--[[
To generate Visual Studio files (in vs2019/ or vs2022/ directory), run:
scripts\premake-regenerate-vs-projects.ps1

I'm using premake5 beta6 from https://premake.github.io/download/

Note about nasm: when providing "-I foo/bar/" flag to nasm.exe, it must be
"foo/bar/" and not just "foo/bar".

Notes about asan in msvc:
https://devblogs.microsoft.com/cppblog/addresssanitizer-asan-for-windows-with-msvc/
https://devblogs.microsoft.com/cppblog/msvc-address-sanitizer-one-dll-for-all-runtime-configurations/

Set this in debugger env properties:
PATH=%PATH%;c:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64
(see https://stackoverflow.com/questions/428085/how-do-i-set-a-path-in-visual-studio)
Make sure you're targeting the righat Configuration / Platform

Reference for warnings:
 4018 - signed/unsigned mismatch
 4057 - function X differs in indirection to slightly different base types
 4090 - different 'const' qualifiers
 4091 - 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared
 4100 - unreferenced formal parameter
 4127 - conditional expression is constant
 4131 - uses old-style declarator
 4189 - local variable is initialized but not referenced, defer macro triggers this
 4204 - non-standard extension: non-constant aggregate initializer
 4206 - non-standard extension: translation unit is empty
 4244 - 64bit, conversion with possible loss of data
 4245 - sign/unsigned mismatch
 4267 - 64bit, conversion with possible loss of data
 4302 - 64bit, type cast truncation
 4305 - 'initializing': truncation from 'double' to 'float'
 4310 - 64bit, cast truncates constant value
 4311 - 64bit, type cast pointer truncation
 4312 - 64bit, conversion to X of greater size
 4324 - 64bit, structure was padded
 4458 - declaraion of X hides class member
 4522 - multiple assignment operators specified
 4530 - exception mismatch
 4611 - interaction between '_setjmp' and C++ object destruction is non-portable
 4702 - unreachable code
 4706 - assignment within conditional expression
 4800 - forcing value to bool (performance warning)
 4819 - The file contains a character that cannot be represented in the current code page
 4838 - conversion from X to Y requires a narrowing conversion
 4996 - POSIX name deprecated

 Linker warning
 4221 - This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library

Prefast:
 28125 - function X must be called in try/except (InitializeCriticalSection)
 28252 - Inconsistent annotation
 28253 - Inconsistent annotation
--]]

newoption {
  trigger = "with-clang",
  description = "use clang-cl.exe instead of cl.exe"
}

-- TODO: test this option
-- usestandardpreprocessor 'On'

-- TODO: try appmanifest
-- files { "hello.appxmanifest" }
-- https://github.com/premake/premake-core/pull/1750/files

include("premake5.files.lua")


-- this is meant to make the binary win7 compatible but
-- does't seem to work
function winver7_defines()
  defines {
    "WIN32",
    "_WIN32",
    -- https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=vs-2019
    "WINVER=0x0601", -- force not using API not available in Win7
    "_WIN32_WINNT=0x0601",
     "NTDDI_VERSION=0x06010000"
  }

  -- v143 is the last that supports windows 7
  toolset "v143"   -- this is the official way in recent Premake versions
end

function winver_latest_defines()
  defines {
    "WIN32",
    "_WIN32",
    -- https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=vs-2019
    "WINVER=0x0605",
    "_WIN32_WINNT=0x0603"
  }
end

function winver_defines()
  winver7_defines()
  -- winver_latest_defines()
end

-- setup WebView2 paths
function webview_conf()
  includedirs { "packages/Microsoft.Web.WebView2.1.0.992.28/build/native/include" }
  filter "platforms:x86"
  libdirs { "packages/Microsoft.Web.WebView2.1.0.992.28/build/native/x86" }
  filter "platforms:x64 or x64_asan"
  libdirs { "packages/Microsoft.Web.WebView2.1.0.992.28/build/native/x64" }
  filter "platforms:arm64"
  libdirs { "packages/Microsoft.Web.WebView2.1.0.992.28/build/native/arm64" }
  filter {}
  links { "WebView2LoaderStatic.lib" }
end

-- to make debug builds faster, we compile stable libraries (freetype, libjpeg etc.)
-- in release mode even in debug builds
function mixed_dbg_rel_conf()
  editandcontinue "Off"

  -- same as in optimized_conf()
  runtime "Release"
  defines { "_HAS_ITERATOR_DEBUGGING=0" }

  filter "configurations:Debug"
  defines { "DEBUG" }

  filter "configurations:DebugFull"
  defines { "DEBUG" }

  filter "configurations:Release*"
  defines { "NDEBUG" }
  optimize "Size"

  -- asan builds: no ltcg
  filter { "configurations:Release*", "platforms:x86 or x64 or arm64" }
  linktimeoptimization "On"
  filter {}
end

-- config for stable libraries where debug build is done with optimization
function optimized_conf()
  editandcontinue "Off"
  optimize "Size"

  -- we mix Deubg / Release compilation between projects
  -- but all linked modules have to use the same type
  -- of c libraries, so we use release C libs
  -- and we disable C++ iterator debugging because it also
  -- must be consistent across modules
  runtime "Release"
  defines { "_HAS_ITERATOR_DEBUGGING=0" }

  filter "configurations:DebugFull"
  defines { "DEBUG" }

  filter "configurations:Debug or Release or ReleaseAnalyze"
  undefines { "DEBUG" }
  defines { "NDEBUG" }
  filter {}

  filter { "configurations:Release*", "platforms:x86 or x64 or arm64" }
  linktimeoptimization "On"
  filter {}
end

-- per-workspace setting that differ in clang-cl.exe vs cl.exe builds
function clang_conf()
  filter "options:with-clang"
      location "vs2022-clang"
      toolset "clang"
      buildoptions { "-fms-compatibility", "-fms-extensions", "-Wno-microsoft-include", "-march=x86-64-v3", "-maes" }

      warnings "Off"
      exceptionhandling "On"
  filter {}

  filter { 'options:not with-clang' }
      warnings "Extra"
      exceptionhandling "Off"
  filter {}
end

function warnings_as_errors()
  filter { "configurations:not ReleaseAnalyze" and "options:not with-clang" }
      fatalwarnings { "All" }
  filter {}
end

function zlib_defines()
  includedirs {
    "ext/zlib",
  }
end

-- add to a project that links zlib
function links_zlib()
  -- links { "zlib-ng" }
  links { "zlib" }
end

-- add to a project that needs to see zlib headers
function uses_zlib()
  --zlib_ng_defines()
  zlib_defines()
end

workspace "SumatraPDF"
  configurations { "Debug", "DebugFull", "Release", "ReleaseAnalyze", }
  platforms { "x86", "x64", "arm64", "x64_asan" }
  startproject "SumatraPDF"

  filter "platforms:x86"
    architecture "x86"
  filter {}

  filter "platforms:x64_asan"
    sanitize { "Address" }
    defines { "ASAN_BUILD=1" }
    incrementallink("Off")
    editandcontinue "Off"
    -- disablewarnings { "4731" }
  filter {}

  filter "platforms:x64 or x64_asan"
    architecture "x86_64"
    -- strangely this is not set by default for rc.exe
    resdefines { "_WIN64" }
  filter {}

  filter "platforms:arm64"
    architecture "ARM64"
  filter {}

  disablewarnings { "4127", "4189", "4324", "4458", "4522", "4611", "4702", "4800", "6319" }
  -- /utf-8 sets both source and execution charset to UTF-8
  -- fixes compilation on non-English Windows (e.g. Chinese) where
  -- default code page doesn't match source file encoding
  buildoptions { "/utf-8" }

  location "this_is_invalid_location"

  filter "action:vs2022"
    location "vs2022"
  filter {}

  clang_conf()

  filter { "platforms:x86", "configurations:Release" }
    targetdir "out/rel32"
  filter { "platforms:x86", "configurations:ReleaseAnalyze" }
    targetdir "out/rel32_prefast"
  filter { "platforms:x86", "configurations:Debug" }
    targetdir "out/dbg32"
  filter { "platforms:x86", "configurations:DebugFull" }
    targetdir "out/dbgfull32"

  filter { "platforms:x64", "configurations:Release" }
    targetdir "out/rel64"
  filter { "platforms:x64", "configurations:ReleaseAnalyze" }
    targetdir "out/rel64_prefast"
  filter { "platforms:x64", "configurations:Debug" }
    targetdir "out/dbg64"
  filter { "platforms:x64", "configurations:DebugFull" }
    targetdir "out/dbgfull64"
  filter {}

  filter { "platforms:x64_asan", "configurations:Release" }
    targetdir "out/rel64_asan"
  filter { "platforms:x64_asan", "configurations:ReleaseAnalyze" }
    targetdir "out/rel64_prefast_asan"
  filter { "platforms:x64_asan", "configurations:Debug" }
    targetdir "out/dbg64_asan"
  filter { "platforms:x64_asan", "configurations:DebugFull" }
    targetdir "out/dbgfull64_asan"
  filter {}

  filter { "platforms:arm64", "configurations:Release" }
    targetdir "out/arm64"
  filter { "platforms:arm64", "configurations:ReleaseAnalyze" }
    targetdir "out/arm64_prefast"
  filter { "platforms:arm64", "configurations:Debug" }
    targetdir "out/dbgarm64"
  filter { "platforms:arm64", "configurations:DebugFull" }
    targetdir "out/dbgfullarm64"
  filter {}

  objdir "%{cfg.targetdir}/obj"

  -- https://github.com/premake/premake-core/wiki/symbols
  -- https://blogs.msdn.microsoft.com/vcblog/2016/10/05/faster-c-build-cycle-in-vs-15-with-debugfastlink/
  symbols "FastLink"
  filter { "configurations:Release" }
    symbols "Full"
  filter {}

  staticruntime "On"
  -- https://github.com/premake/premake-core/wiki/flags
  multiprocessorcompile("On")
  mapfile("On")
  rtti "Off"

  winver_defines()

  project "unrar"
    kind "StaticLib"
    language "C++"
    optimized_conf()
    defines { "UNRAR", "RARDLL", "SILENT" }
    -- os.hpp redefines WINVER, is there a better way?
    disablewarnings { "4005", "4100", "4201", "4211", "4244", "4310", "4389", "4456", "4459", "4505", "4701", "4702", "4706", "4709", "4731", "4828", "4996" }
    exceptionhandling "On"

    includedirs { "ext/unrar" }
    unrar_files()

  project "libdjvu"
    kind "StaticLib"
    characterset("MBCS")
    language "C++"
    optimized_conf()
    defines {
      "_CRT_SECURE_NO_WARNINGS",
      "NEED_JPEG_DECODER",
      "WINTHREADS=1",
      "DDJVUAPI=/**/",
      "MINILISPAPI=/**/",
      "DEBUGLVL=0"
    }
    filter { "platforms:x64_asan" }
      defines { "DISABLE_MMX" }
    filter {}
    exceptionhandling "On"
    disablewarnings { "4100", "4189", "4244", "4267", "4302", "4311", "4312", "4505" }
    disablewarnings { "4456", "4457", "4459", "4701", "4702", "4703", "4706" }
    includedirs { "ext/libjpeg-turbo" }
    libdjvu_files()

  project "chm"
    kind "StaticLib"
    language "C"
    optimized_conf()
    defines { "_CRT_SECURE_NO_WARNINGS" }
    disablewarnings { "4018", "4244", "4267", "4996" }
    files { "ext/CHMLib/*.c", "ext/CHMLib/*.h" }

  project "libarchive"
    kind "StaticLib"
    language "C"
    optimized_conf()
    defines {
      "_CRT_SECURE_NO_WARNINGS",
      "LIBARCHIVE_STATIC",
      'PLATFORM_CONFIG_H="config_windows.h"',
    }
    warnings_as_errors()
    disablewarnings { "4018", "4054", "4055", "4090", "4098", "4100", "4127", "4130","4146", "4152", "4200", "4201", "4244", "4245", "4267", "4305", "4389", "4456", "4457", "4706", "4996" }
    uses_zlib()
    includedirs { "ext/libarchive/libarchive" }
    libarchive_files()
    -- bzip2 support for libarchive
    defines { "BZ_NO_STDIO" }
    includedirs { "ext/bzip2" }
    files { "ext/bzip2/blocksort.c", "ext/bzip2/bzlib.c", "ext/bzip2/bz_internal_error.c",
            "ext/bzip2/compress.c", "ext/bzip2/crctable.c", "ext/bzip2/decompress.c",
            "ext/bzip2/huffman.c", "ext/bzip2/randtable.c" }
    -- LZMA files needed by LzmaSimpleArchive in utils (previously provided by unarrlib)
    includedirs { "ext/lzma/C" }
    files { "ext/lzma/C/LzmaDec.c", "ext/lzma/C/Bra86.c", "ext/lzma/C/Bra.c" }
    -- liblzma for LZMA/LZMA2/XZ decompression (needed for 7zip support in libarchive)
    defines { "HAVE_CONFIG_H", "LZMA_API_STATIC" }
    includedirs { "ext/liblzma/api", "ext/liblzma/common", "ext/liblzma/check",
                  "ext/liblzma/delta", "ext/liblzma/lz", "ext/liblzma/lzma",
                  "ext/liblzma/rangecoder", "ext/liblzma/simple", "ext/liblzma" }
    files {
      "ext/liblzma/common/alone_decoder.c",
      "ext/liblzma/common/auto_decoder.c",
      "ext/liblzma/common/block_decoder.c",
      "ext/liblzma/common/block_header_decoder.c",
      "ext/liblzma/common/block_util.c",
      "ext/liblzma/common/common.c",
      "ext/liblzma/common/filter_common.c",
      "ext/liblzma/common/filter_decoder.c",
      "ext/liblzma/common/filter_flags_decoder.c",
      "ext/liblzma/common/index.c",
      "ext/liblzma/common/index_decoder.c",
      "ext/liblzma/common/index_hash.c",
      "ext/liblzma/common/stream_decoder.c",
      "ext/liblzma/common/stream_flags_common.c",
      "ext/liblzma/common/stream_flags_decoder.c",
      "ext/liblzma/common/vli_decoder.c",
      "ext/liblzma/common/vli_size.c",
      "ext/liblzma/check/check.c",
      "ext/liblzma/check/crc32_fast.c",
      "ext/liblzma/check/crc64_fast.c",
      "ext/liblzma/lz/lz_decoder.c",
      "ext/liblzma/lzma/lzma_decoder.c",
      "ext/liblzma/lzma/lzma2_decoder.c",
      "ext/liblzma/rangecoder/price_table.c",
      "ext/liblzma/delta/delta_common.c",
      "ext/liblzma/delta/delta_decoder.c",
      "ext/liblzma/simple/simple_coder.c",
      "ext/liblzma/simple/simple_decoder.c",
      "ext/liblzma/simple/x86.c",
    }

  project "libwebp"
    kind "StaticLib"
    language "C"
    optimized_conf()
    disablewarnings { "4204", "4244", "4057", "4245", "4310", "4701" }
    includedirs { "ext/libwebp" }
    libwebp_files()

    -- ARGS = "-Isrc\libdav1d_entrypoint.a.p" "-Isrc" "-I..\src" "-I." "-I.." "-Iinclude\dav1d" "-I..\include\dav1d" "-Iinclude" "-I..\include" "-I..\include\compat\msvc" "-DNDEBUG" "/MD" "/nologo" "/showIncludes" "/utf-8" "/W3" "/O2" "/Gw" "-D_POSIX_C_SOURCE=200112L" "-wd4028" "-wd4090" "-wd4996" "/Fdsrc\libdav1d_entrypoint.a.p\thread_task.c.pdb"

    -- for asm files
    -- build src/libdav1d.a.p/looprestoration_avx2.obj: CUSTOM_COMMAND_DEP ../src/x86/looprestoration_avx2.asm | C$:/Users/kjk/AppData/Local/bin/NASM/nasm.EXE
    -- COMMAND = "C:\Users\kjk\AppData\Local\bin\NASM\nasm.EXE" "-f" "win64" "-I" "C:/Users/kjk/src/dav1d/src/" "-I" "C:/Users/kjk/src/dav1d/build/" "-MQ" "src/libdav1d.a.p/looprestoration_avx2.obj" "-MF" "src/libdav1d.a.p/looprestoration_avx2.obj.ndep" "../src/x86/looprestoration_avx2.asm" "-o" "src/libdav1d.a.p/looprestoration_avx2.obj"

  project "libheif"
    kind "StaticLib"
    language "C++"
    cppdialect "C++latest"
    optimized_conf()
    defines { "_CRT_SECURE_NO_WARNINGS", "HAVE_DAV1D", "LIBHEIF_STATIC_BUILD" }
    includedirs { "ext/libheif/libheif", "ext/libheif/libheif/api", "ext/dav1d/include" }
    disablewarnings { "4018", "4065", "4100", "4101", "4146", "4244", "4245", "4267", "4273", "4319", "4456", "4701", "4703", "4805", "4996" }
    -- TODO: I don't want RTTI and /EHsc
    rtti "On"
    buildoptions { "/EHsc" }
    libheif_files()

  project "dav1d"
    kind "StaticLib"
    language "C"
    optimized_conf()
    defines { "_CRT_SECURE_NO_WARNINGS" }
    filter { 'platforms:x86' }
    defines { "ARCH_X86_32=1", "ARCH_X86_64=0", "__SSE2__" }
    filter { 'platforms:x64 or x64_asan' }
    defines { "ARCH_X86_32=0", "ARCH_X86_64=1" }
    filter {}
    disablewarnings { "4057", "4090", "4100", "4152", "4201", "4244", "4245", "4456", "4457", "4701", "4703", "4706", "4819", "4996", "5287" }
    includedirs { "ext/dav1d/include/compat/msvc", "ext/dav1d", "ext/dav1d/include" }
    -- nasm.exe -I .\ext\libjpeg-turbo\simd\
    -- -I .\ext\libjpeg-turbo\win\ -f win32
    -- -o .\obj-rel\jpegturbo\jsimdcpu.obj
    -- .\ext\libjpeg-turbo\simd\jsimdcpu.asm
    filter { 'files:**.asm', 'platforms:x86' }
      buildmessage '%{file.relpath}'
      buildoutputs { '%{cfg.objdir}/%{file.basename}_asm.obj' }
      buildcommands {
        '..\\bin\\nasm.exe -f win32 -DPREFIX=1 -DARCH_X86_64=0 -DARCH_X86_32=1 -I ../ext/dav1d/src -I ../ext/dav1d/include -o "%{cfg.objdir}/%{file.basename}_asm.obj" "%{file.relpath}"'
      }
    filter {}
    filter { 'files:**.asm', 'platforms:x64 or x64_asan' }
      buildmessage '%{file.relpath}'
      buildoutputs { '%{cfg.objdir}/%{file.basename}_asm.obj' }
      buildcommands {
        '..\\bin\\nasm.exe -f win64 -DARCH_X86_64=1 -DARCH_X86_32=0 -D__x86_64__ -DWIN64 -DMSVC -I ../ext/dav1d/src -I ../ext/dav1d/include -o "%{cfg.objdir}/%{file.basename}_asm.obj" "%{file.relpath}"'
      }
    filter {}

    dav1d_files()
    filter { 'platforms:x86 or x64 or x64_asan' }
      dav1d_x68_files()
    filter {}

  project "zlib"
    kind "StaticLib"
    language "C"
    optimized_conf()
    disablewarnings { "4131", "4244", "4245", "4267", "4996" }
    zlib_files()

-- to make Visual Studio solution smaller
-- combine 9 libs only used by mupdf into a single project
-- instead of having 9 projects

  project "mupdf-libs"
    kind "StaticLib"
    language "C"
    optimized_conf()

    -- zlib
    -- disablewarnings { "4131", "4244", "4245", "4267", "4996" }
    -- zlib_files()

    -- libjpeg-turbo
    defines { "_CRT_SECURE_NO_WARNINGS" }
    disablewarnings { "4013", "4018", "4100", "4244", "4245", "4819" }
    includedirs { "ext/libjpeg-turbo", "ext/libjpeg-turbo/simd" }
    -- nasm.exe -I .\ext\libjpeg-turbo\simd\
    -- -I .\ext\libjpeg-turbo\win\ -f win32
    -- -o .\obj-rel\jpegturbo\jsimdcpu.obj
    -- .\ext\libjpeg-turbo\simd\jsimdcpu.asm
    filter { 'files:**.asm', 'platforms:x86' }
      buildmessage '%{file.relpath}'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\nasm.exe -f win32 -I ../ext/libjpeg-turbo/simd/ -I ../ext/libjpeg-turbo/win/ -o "%{cfg.objdir}/%{file.basename}.obj" "%{file.relpath}"'
      }
    filter {}
    filter { 'files:**.asm', 'platforms:x64 or x64_asan' }
      buildmessage '%{file.relpath}'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\nasm.exe -f win64 -D__x86_64__ -DWIN64 -DMSVC -I ../ext/libjpeg-turbo/simd/ -I ../ext/libjpeg-turbo/win/ -o "%{cfg.objdir}/%{file.basename}.obj" "%{file.relpath}"'
      }
    filter {}
    libjpeg_turbo_files()

    -- jbig2dec
    defines { "_CRT_SECURE_NO_WARNINGS", "HAVE_STRING_H=1", "JBIG_NO_MEMENTO" }
    disablewarnings { "4018", "4100", "4146", "4244", "4267", "4456", "4701" }
    includedirs { "ext/jbig2dec" }
    jbig2dec_files()

    -- openjpeg
    disablewarnings { "4100", "4244", "4310", "4389", "4456" }
    -- openjpeg has opj_config_private.h for such over-rides
    -- but we can't change it because we bring openjpeg as submodule
    -- and we can't provide our own in a different directory because
    -- msvc will include the one in ext/openjpeg/src/lib/openjp2 first
    -- because #include "opj_config_private.h" searches current directory first
    defines { "_CRT_SECURE_NO_WARNINGS", "USE_JPIP", "OPJ_STATIC", "OPJ_EXPORTS" }
    openjpeg_files()

    -- freetype
    defines {
      "FT2_BUILD_LIBRARY",
      "FT_CONFIG_MODULES_H=\"slimftmodules.h\"",
      "FT_CONFIG_OPTIONS_H=\"slimftoptions.h\"",
      "FT_CONFIG_OPTION_USE_BROTLI",
    }
    disablewarnings { "4018", "4100", "4101", "4244", "4267", "4312", "4701", "4706", "4996" }
    includedirs { "mupdf/scripts/freetype", "ext/freetype/include" }
    freetype_files()

    -- lcms2
    disablewarnings { "4100" }
    includedirs { "ext/lcms2/include" }
    lcms2_files()

    -- harfbuzz
    includedirs { "ext/harfbuzz/src/hb-ucdn", "mupdf/scripts/freetype", "ext/freetype/include" }
    defines {
      --"_CRT_SECURE_NO_WARNINGS",
      "HAVE_FALLBACK=1",
      "HAVE_OT",
      "HAVE_UCDN",
      "HAVE_FREETYPE",
    }
    filter "configurations:Debug or DebugFull"
    defines {
      "HAVE_ATEXIT",
      "hb_malloc_impl=sumatra_hb_malloc",
      "hb_calloc_impl=sumatra_hb_calloc",
      "hb_realloc_impl=sumatra_hb_realloc",
      "hb_free_impl=sumatra_hb_free"
    }
    filter "configurations:Release or ReleaseAnalyze"
      defines {
        "hb_malloc_impl=fz_hb_malloc",
        "hb_calloc_impl=fz_hb_calloc",
        "hb_realloc_impl=fz_hb_realloc",
        "hb_free_impl=fz_hb_free"
      }
    filter {}
    disablewarnings { "4805", "4100", "4146", "4244", "4245", "4267", "4456", "4457", "4459", "4701", "4702", "4706" }
    harfbuzz_files()

    -- mujs
    includedirs { "ext/mujs" }
    disablewarnings { "4090", "4100", "4310", "4702", "4706" }
    files { "ext/mujs/one.c", "ext/mujs/mujs.h" }

    -- gumbo
    disablewarnings { "4018", "4100", "4132", "4204", "4244", "4245", "4267",
      "4305", "4306", "4389", "4456", "4701" }
    includedirs { "ext/gumbo-parser/include", "ext/gumbo-parser/visualc/include" }
    gumbo_files()

    -- extract
    disablewarnings { "4005", "4201", "4130" }
    includedirs { "ext/extract/include" }
    uses_zlib()
    extract_files()

    -- brotli
    includedirs { "ext/brotli/c/include" }
    brotli_files()

    -- libheif
    defines { "LIBHEIF_STATIC_BUILD" }

    function fonts()
      files {

        "mupdf/resources/fonts/urw/Dingbats.cff",
        "mupdf/resources/fonts/urw/NimbusMonoPS-Regular.cff",
        "mupdf/resources/fonts/urw/NimbusMonoPS-Italic.cff",
        "mupdf/resources/fonts/urw/NimbusMonoPS-Bold.cff",
        "mupdf/resources/fonts/urw/NimbusMonoPS-BoldItalic.cff",
        "mupdf/resources/fonts/urw/NimbusRoman-Regular.cff",
        "mupdf/resources/fonts/urw/NimbusRoman-Italic.cff",
        "mupdf/resources/fonts/urw/NimbusRoman-Bold.cff",
        "mupdf/resources/fonts/urw/NimbusRoman-BoldItalic.cff",
        "mupdf/resources/fonts/urw/NimbusSans-Regular.cff",
        "mupdf/resources/fonts/urw/NimbusSans-Italic.cff",
        "mupdf/resources/fonts/urw/NimbusSans-Bold.cff",
        "mupdf/resources/fonts/urw/NimbusSans-BoldItalic.cff",
        "mupdf/resources/fonts/urw/StandardSymbolsPS.cff",
        "mupdf/resources/fonts/droid/DroidSansFallbackFull.ttf",
        "mupdf/resources/fonts/sil/CharisSIL.cff",
        "mupdf/resources/fonts/sil/CharisSIL-Bold.cff",
        "mupdf/resources/fonts/sil/CharisSIL-Italic.cff",
        "mupdf/resources/fonts/sil/CharisSIL-BoldItalic.cff",

        "mupdf/resources/fonts/noto/NotoSans-Regular.otf",
        "mupdf/resources/fonts/noto/NotoSansMath-Regular.otf",
        "mupdf/resources/fonts/noto/NotoSansSymbols-Regular.otf",
        "mupdf/resources/fonts/noto/NotoSansSymbols2-Regular.otf",
        "mupdf/resources/fonts/noto/NotoEmoji-Regular.ttf",
        "mupdf/resources/fonts/noto/NotoMusic-Regular.otf",
        "mupdf/resources/fonts/noto/NotoSerif-Regular.otf",
      }

      filter { 'files:**.cff', 'platforms:x86' }
      buildmessage 'bin2coff %{file.basename}.cff (x86)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_cff x86'
      }
      filter { 'files:**.cff', 'platforms:x64 or x64_asan' }
      buildmessage 'bin2coff %{file.basename}.cff (x64)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_cff x86_64'
      }
      filter { 'files:**.cff', 'platforms:arm64' }
      buildmessage 'bin2coff %{file.basename}.cff (arm64)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_cff ARM64'
      }
      filter {}

      filter { 'files:**.ttf', 'platforms:x86' }
      buildmessage 'bin2coff %{file.basename}.ttf (x86)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_ttf x86'
      }
      filter { 'files:**.ttf', 'platforms:x64 or x64_asan' }
      buildmessage 'bin2coff %{file.basename}.ttf (x64)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_ttf x86_64'
      }
      filter { 'files:**.ttf', 'platforms:arm64' }
      buildmessage 'bin2coff %{file.basename}.ttf (arm64)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_ttf ARM64'
      }
      filter {}

      filter { 'files:**.otf', 'platforms:x86' }
      buildmessage 'bin2coff %{file.basename}.otf (x86)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_otf x86'
      }
      filter { 'files:**.otf', 'platforms:x64 or x64_asan' }
      buildmessage 'bin2coff %{file.basename}.otf (x64)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_otf x86_64'
      }
      filter { 'files:**.otf', 'platforms:arm64' }
      buildmessage 'bin2coff %{file.basename}.otf (arm64)'
      buildoutputs { '%{cfg.objdir}/%{file.basename}.obj' }
      buildcommands {
        '..\\bin\\bin2coff.exe "%{file.relpath}" "%{cfg.objdir}/%{file.basename}.obj" _binary_%{file.basename}_otf ARM64'
      }
      filter {}
    end

  project "mupdf"
    kind "StaticLib"
    language "C"
    mixed_dbg_rel_conf()
    -- for openjpeg, OPJ_STATIC is alrady defined in load-jpx.c
    -- so we can't double-define it
    defines { "USE_JPIP", "OPJ_EXPORTS", "HAVE_LCMS2MT=1" }
    defines { "OPJ_STATIC", "SHARE_JPEG" }
    -- this defines which fonts are to be excluded from being included directly
    -- we exclude the very big cjk fonts
    defines { "TOFU_NOTO", "TOFU_CJK_LANG", "TOFU_NOTO_SUMATRA" }
    defines { "FZ_ENABLE_PDF=1", "FZ_ENABLE_SVG=1", "FZ_ENABLE_BROTLI=1", "FZ_ENABLE_BARCODE=0", "FZ_ENABLE_JS=1", "FZ_ENABLE_HYPHEN=0" }
    defines { "HAVE_LIBARCHIVE", "LIBARCHIVE_STATIC" }

    filter { "platforms:arm64" }
    defines { "ARCH_HAS_NEON=1" }
    filter {}

    disablewarnings {
      "4005", "4013", "4018", "4057", "4100", "4115", "4130", "4132", "4200", "4204", "4206", "4210",
      "4245", "4267", "4295", "4305", "4389", "4456", "4457", "4703", "4706", "4819", "5286"
    }
    -- force including mupdf/scripts/openjpeg/opj_config_private.h
    -- with our build over-rides

    uses_zlib()
    includedirs {
      "mupdf/include",
      "mupdf/generated",
      "ext/jbig2dec",
      "ext/libjpeg-turbo",
      "ext/openjpeg/src/lib/openjp2",
      "mupdf/scripts/freetype",
      "ext/freetype/include",
      "ext/mujs",
      "ext/brotli/c/include",
      "ext/harfbuzz/src",
      "ext/lcms2/include",
      "ext/gumbo-parser/src",
      "ext/extract/include",
      "ext/libarchive",
    }
    fonts()

    mupdf_files()
    links { "mupdf-libs", "libarchive" }
    -- links { "mupdf-libs", "zlib", "freetype", "openjpeg", "libjpeg-turbo", "jbig2dec", "lcms2", "harfbuzz", "mujs", "gumbo" }

    -- mupdf
    -- this fixes "NAN" is not a constant in some version of msvc
    -- without this it's #define _UCRT_NAN (__ucrt_int_to_float(0x7FC00000))
    defines { "_UCRT_NOISY_NAN" }

  project "libmupdf"
    kind "SharedLib"
    language "C"
    optimized_conf()
    disablewarnings { "4206", "4702" }
    defines { "FZ_ENABLE_PDF=1", "FZ_ENABLE_SVG=1", "FZ_ENABLE_BROTLI=1", "FZ_ENABLE_BARCODE=0", "FZ_ENABLE_JS=1", "FZ_ENABLE_HYPHEN=0" }

    filter { "platforms:arm64" }
    defines { "ARCH_HAS_NEON=1" }
    filter {}

    -- premake has logic in vs2010_vcxproj.lua that only sets PlatformToolset
    -- if there is a c/c++ file, so we add a no-op cpp file to force This logic
    files { "src/libmupdf.rc", "src/libmupdf.def", "src/no_op_for_premake.cpp" }
    implibname "libmupdf"
    -- TODO: is thre a better way to do it?
    -- linkoptions { "/DEF:..\\src\\libmupdf.def", "-IGNORE:4702" }
    linkoptions { "-IGNORE:4702" }
    links_zlib()
    links { "mupdf", "libdjvu", "libwebp", "dav1d", "libheif" }
    links {
      "advapi32", "kernel32", "user32", "gdi32", "comdlg32",
      "shell32", "windowscodecs", "comctl32", "msimg32",
      "winspool", "wininet", "urlmon", "gdiplus", "ole32",
      "oleAut32", "shlwapi", "version", "crypt32"
    }

  project "utils"
    kind "StaticLib"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    warnings_as_errors()
    filter "configurations:ReleaseAnalyze"
    -- TODO: somehow /analyze- is default which creates warning about
    -- over-ride from cl.exe. Don't know how to disable the warning
    buildoptions { "/analyze" }
    disablewarnings { "28125", "28252", "28253" }
    filter {}

    -- QITABENT in shlwapi.h has incorrect definition and causes 4838
    disablewarnings { "4100", "4267", "4457", "4838" }
    uses_zlib()
    defines { "LIBHEIF_STATIC_BUILD", "LIBARCHIVE_STATIC" }
    includedirs { "src", "ext/lzma/C" }
    includedirs { "ext/libheif/libheif/api", "ext/libwebp/src", "ext/dav1d/include", "ext/libarchive", "mupdf/include" }
    utils_files()

---- executables

  project "test_util"
    kind "ConsoleApp"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    disablewarnings { "4838" }
    includedirs { "src" }
    test_util_files()
    links { "gdiplus", "comctl32", "shlwapi", "Version", "wininet", "shcore", "wintrust", "crypt32" }

  project "bin2coff"
    kind "ConsoleApp"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    disablewarnings { "4200", "4838" }
    includedirs { "src" }
    bin2coff_files()
    links { "gdiplus", "comctl32", "shlwapi", "Version" }

  project "PdfFilter"
    kind "SharedLib"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    disablewarnings { "4100", "4838" }
    defines { "HAVE_LIBARCHIVE", "LIBARCHIVE_STATIC" }
    filter { "configurations:Debug" }
    defines { "BUILD_TEX_IFILTER", "BUILD_EPUB_IFILTER" }
    filter {}
    includedirs { "src", "src/wingui", "mupdf/include", "ext/libarchive" }
    search_filter_files()
    links { "utils", "unrar", "libmupdf", "libarchive" }
    links { "comctl32", "gdiplus", "shlwapi", "version", "wininet", "wintrust", "crypt32" }

  -- project "PdfFilter2"
  --   kind "SharedLib"
  --   language "C++"
  --   cppdialect "C++latest"
  --   mixed_dbg_rel_conf()
  --   disablewarnings { "4100", "4838" }
  --   includedirs { "src", "src/wingui" }
  --   search_filter2_files()
  --   links { "comctl32", "gdiplus", "shlwapi", "version", "wininet", "wintrust", "crypt32" }

  -- project "PdfPreview2"
  --   kind "SharedLib"
  --   language "C++"
  --   cppdialect "C++latest"
  --   mixed_dbg_rel_conf()
  --   disablewarnings { "4100", "4838" }
  --   includedirs {
  --     "src", "src/wingui"
  --   }
  --   pdf_preview2_files()
  --   -- TODO: "chm" should only be for Debug config but doing links { "chm" }
  --   -- in the filter breaks linking by setting LinkLibraryDependencies to false
  --   links { "comctl32", "gdiplus", "msimg32", "shlwapi", "version", "wininet", "wintrust", "crypt32" }

  project "PdfPreview"
    kind "SharedLib"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    disablewarnings { "4100", "4838" }
    defines { "HAVE_LIBARCHIVE", "LIBARCHIVE_STATIC" }
    includedirs {
      "src", "src/wingui", "mupdf/include",
      "ext/libdjvu", "ext/CHMLib",
      "ext/libarchive",
    }
    pdf_preview_files()
    -- TODO: "chm" should only be for Debug config but doing links { "chm" }
    -- in the filter breaks linking by setting LinkLibraryDependencies to false
    links { "utils", "unrar", "libmupdf", "libarchive", "chm" }
    links { "comctl32", "gdiplus", "msimg32", "shlwapi", "version", "wininet", "wintrust", "crypt32" }

  -- a single static executable
  project "SumatraPDF"
    kind "WindowedApp"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    warnings_as_errors()
    entrypoint "WinMainCRTStartup"
    manifest("Off")
    defines { "LIBARCHIVE_STATIC" }
    includedirs { "src", "mupdf/include" }
    includedirs { "ext/synctex", "ext/libdjvu", "ext/CHMLib", "ext/libarchive", "ext/md4c/src" }

    includedirs { "ext/darkmodelib/include" }
    defines { "_DARKMODELIB_NO_INI_CONFIG" }
    darkmodelib_files()

    webview_conf()

    synctex_files()
    mui_files()
    wingui_files()
    uia_files()
    engines_files()
    sumatrapdf_files()
    md4c_files()
    pdf_darkmode_files()

    debugdir(".")

    defines { "_CRT_SECURE_NO_WARNINGS" }
    defines { "DISABLE_DOCUMENT_RESTRICTIONS" }

    filter "configurations:ReleaseAnalyze"
    -- TODO: somehow /analyze- is default which creates warning about
    -- over-ride from cl.exe. Don't know how to disable the warning
    buildoptions { "/analyze" }
    disablewarnings { "28125", "28252", "28253" }
    filter {}

    -- for synctex
    disablewarnings { "4100", "4244", "4267", "4701", "4702", "4703", "4706", "4819", "6324" }
    uses_zlib()
    includedirs { "ext/synctex" }

    -- for uia
    disablewarnings { "4302", "4311", "4838" }

    links_zlib()
    links {
      "libdjvu", "libwebp", "dav1d", "libheif", "mupdf", "libarchive", "utils", "unrar", "chm"
    }
    links {
      "comctl32", "delayimp", "gdiplus", "msimg32", "shlwapi", "urlmon",
      "version", "windowscodecs", "wininet", "uiautomationcore.lib", "uxtheme", "wintrust", "crypt32"
    }
    -- this is to prevent dll hijacking
    linkoptions { "/DELAYLOAD:gdiplus.dll /DELAYLOAD:msimg32.dll /DELAYLOAD:shlwapi.dll" }
    linkoptions { "/DELAYLOAD:urlmon.dll /DELAYLOAD:wininet.dll" }
    linkoptions { "/DELAYLOAD:uiautomationcore.dll" }
    filter "platforms:x64_asan"
    linkoptions { "/INFERASANLIBS" }
    filter {}
    dependson { "test_util" }
    prebuildcommands { "..\\bin\\MakeLZSA.exe ..\\translations\\translations.txt.lzsa ..\\translations\\translations-good.txt:translations-good.txt" }

  -- a dll version where most functionality is in libmupdf.dll
  project "SumatraPDF-dll"
    kind "WindowedApp"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()
    warnings_as_errors()
    entrypoint "WinMainCRTStartup"
    manifest("Off")
    defines { "LIBARCHIVE_STATIC" }
    includedirs { "src", "mupdf/include" }
    includedirs { "ext/synctex", "ext/libdjvu", "ext/CHMLib", "ext/libarchive", "ext/md4c/src" }
    includedirs { "ext/darkmodelib/include" }

    includedirs { "ext/darkmodelib/include" }
    defines { "_DARKMODELIB_NO_INI_CONFIG" }
    darkmodelib_files()

    synctex_files()
    mui_files()
    wingui_files()
    uia_files()
    engines_files()
    sumatrapdf_files()
    md4c_files()
    pdf_darkmode_noop_files()

    webview_conf()

    debugdir(".")

    defines { "_CRT_SECURE_NO_WARNINGS" }
    defines { "DISABLE_DOCUMENT_RESTRICTIONS" }

    filter "configurations:ReleaseAnalyze"
    -- TODO: somehow /analyze- is default which creates warning about
    -- over-ride from cl.exe. Don't know how to disable the warning
    buildoptions { "/analyze" }
    disablewarnings { "28125", "28252", "28253" }
    filter {}

    -- for synctex
    disablewarnings { "4100", "4244", "4267", "4701", "4702", "4703", "4706", "4819", "6324" }
    uses_zlib()
    includedirs { "ext/synctex" }

    -- for uia
    disablewarnings { "4302", "4311", "4838" }

    disablewarnings { "4819" }

    resdefines { "INSTALL_PAYLOAD_ZIP=.\\%{cfg.targetdir}\\InstallerData.dat" }

    files { "src/MuPDF_Exports.cpp" }

    links {
      "libmupdf", "unrar", "libarchive", "utils", "chm"
    }
    links {
      "comctl32", "delayimp", "gdiplus", "msimg32", "shlwapi", "urlmon",
      "version", "wininet", "d2d1.lib", "uiautomationcore.lib", "uxtheme", "wintrust", "crypt32"
    }
    -- this is to prevent dll hijacking
    linkoptions { "/DELAYLOAD:libmupdf.dll" }
    linkoptions { "/DELAYLOAD:gdiplus.dll /DELAYLOAD:msimg32.dll /DELAYLOAD:shlwapi.dll" }
    linkoptions { "/DELAYLOAD:urlmon.dll /DELAYLOAD:wininet.dll" }
    linkoptions { "/DELAYLOAD:uiautomationcore.dll" }
    dependson { "PdfFilter", "PdfPreview", "test_util" }
    prebuildcommands { "..\\bin\\MakeLZSA.exe ..\\translations\\translations.txt.lzsa ..\\translations\\translations-good.txt:translations-good.txt" }
    prebuildcommands { "cd %{cfg.targetdir} & ..\\..\\bin\\MakeLZSA.exe InstallerData.dat libmupdf.dll:libmupdf.dll PdfFilter.dll:PdfFilter.dll PdfPreview.dll:PdfPreview.dll" }

workspace "MakeLZSA"
  configurations { "Debug", "Release" }
  platforms { "x86", "x64", "arm64", "x64_asan" }
  startproject "MakeLZSA"

  filter "platforms:x86"
  architecture "x86"
  filter {}

  filter "platforms:x64_asan"
    sanitize { "Address" }
    incrementallink("Off")
    editandcontinue "Off"
  filter {}

  filter "platforms:x64 or x64_asan"
  architecture "x86_64"
  -- strangely this is not set by default for rc.exe
  resdefines { "_WIN64" }
  filter {}

  disablewarnings { "4127", "4189", "4324", "4458", "4522", "4611", "4702", "4800", "6319" }

  location "this_is_invalid_location"

  filter "action:vs2022"
    location "vs2022"
  filter {}

  clang_conf()

  filter { "platforms:x86", "configurations:Release" }
    targetdir "out/rel32"
  filter { "platforms:x86", "configurations:Debug" }
    targetdir "out/dbg32"
  filter {}

  filter { "platforms:x64", "configurations:Release" }
    targetdir "out/rel64"
  filter { "platforms:x64", "configurations:Debug" }
    targetdir "out/dbg64"
  filter {}

  filter { "platforms:x64_asan", "configurations:Release" }
    targetdir "out/rel64_asan"
  filter { "platforms:x64_asan", "configurations:Debug" }
    targetdir "out/dbg64_asan"
  filter {}

  objdir "%{cfg.targetdir}/obj"

  -- https://github.com/premake/premake-core/wiki/symbols
  -- https://blogs.msdn.microsoft.com/vcblog/2016/10/05/faster-c-build-cycle-in-vs-15-with-debugfastlink/
  symbols "Full"
  staticruntime "On"
  -- https://github.com/premake/premake-core/wiki/flags

  fatalwarnings { "All" }
  multiprocessorcompile("On")
  mapfile("On")

  winver_defines()

  project "MakeLZSA"
    kind "ConsoleApp"
    language "C++"
    cppdialect "C++latest"
    mixed_dbg_rel_conf()

    makelzsa_files()
    disablewarnings { "4131", "4244", "4245", "4267", "4996" }
    includedirs { "src", "ext/lzma/C" }

    -- for zlib
    disablewarnings { "4131", "4244", "4245", "4267", "4996" }
    zlib_files()
    uses_zlib()

    links { "shlwapi", "version", "comctl32", "wininet" }
