diff --git a/.gitignore b/.gitignore
index bd45adc96..de42b2d7e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
[Rr]elease/
/MSVC_*
.libs/
+.vs/
# release files
/libtomcrypt-*
diff --git a/premake4.lua b/premake4.lua
new file mode 100644
index 000000000..e5b822ecc
--- /dev/null
+++ b/premake4.lua
@@ -0,0 +1,467 @@
+--[[
+ This premake4.lua in conjunction with premake4 will enable you to generate
+ projects and solutions for a range of Visual Studio (2003 through 2022).
+
+ Simply have premake4 in your PATH and run (adjust the version as needed):
+
+ premake4 vs2022
+
+ You can get a code-signed Windows binary of premake4 from:
+ * https://sourceforge.net/projects/windirstat/files/premake-stable/
+ * https://osdn.net/projects/windirstat/storage/historical/premake-stable/
+ * https://github.com/windirstat/premake-stable/releases/
+]]
+-- SPDX-License-Identifier: Unlicense
+
+local action = _ACTION or ""
+local tgtname = "tomcrypt"
+local tommath_dir = _OPTIONS["tommath-directory"] or "../libtommath"
+local transformMN = function (input) -- transform the macro names for older Visual Studio versions
+ local new_map = { vs2003 = 0, vs2005 = 0, vs2008 = 0 }
+ local replacements = { Platform = "PlatformName", Configuration = "ConfigurationName" }
+ if new_map[action] ~= nil then
+ for k,v in pairs(replacements) do
+ if input:find(k) then
+ input = input:gsub(k, v)
+ end
+ end
+ end
+ return input
+end
+
+newoption { trigger = "no-embed-tommath", description = "Do not embed libtommath in this project by default" }
+newoption { trigger = "tommath-directory", value = "DIR", description = "Provide directory in which libtommath sources are to be found (defaults to ../libtommath)" }
+newoption { trigger = "no-suffix", description = "Disable appending suffix based on target configuration to file stem" }
+
+solution ("libtomcrypt")
+ local tgtdir = "MSVC_" .. action
+ local outdir = tgtdir .. "\\$(" .. transformMN("Configuration") .. ")_$(" .. transformMN("Platform") .. ")"
+
+ configurations {"Debug", "Release"}
+ platforms (iif(action < "vs2005", {"x32"}, {"x32", "x64"}))
+ location ('.')
+
+ project ("libtomcrypt")
+ uuid ("E3802982-DCB6-4D85-A2BD-6B08F0657E79")
+ language ("C")
+ kind ("StaticLib")
+ flags {"StaticRuntime", "NoPCH", }
+ targetname ("tomcrypt")
+ flags {"Unicode", "NativeWChar", }
+ targetdir (tgtdir .. "\\$(ProjectName)")
+ objdir (outdir .. "\\Intermediate\\$(ProjectName)")
+ includedirs {"src/headers", tommath_dir,}
+ defines {"WIN32_LEAN_AND_MEAN", "WINVER=0x0501", "_CRT_SECURE_NO_WARNINGS", "_CRT_NONSTDC_NO_DEPRECATE", "LTC_NO_PROTOTYPES=1", "USE_LTM=1", "LTM_DESC=1", "LTC_SOURCE=1"} -- defines from the command line without value default to 1!
+ buildoptions {"/Z7", "/W3", "/wd4820",} --"/wd4146", "/wd4127", "/wd4668", "/wd4710", "/wd4711", }
+ -- /Z7 for a static lib includes all debug symbols inside the object files, meaning there is no need to distribute PDB _and_ .lib file
+ links {"libtommath"}
+
+ excludes
+ {
+ "Backup*.*",
+ }
+
+ files
+ {
+ "src/**.c",
+ "src/headers/*.h",
+ "*.md", "*.rst", "premake4.lua",
+ }
+
+ vpaths
+ {
+ ["Header Files/*"] = { "src/headers/*.h", },
+ ["Source Files/*"] = { "src/**.c", },
+ ["*"] = { "premake4.lua", "**.md", "**.rst", },
+ }
+
+ configuration {"Debug"}
+ defines {"_DEBUG"}
+
+ configuration {"Release"}
+ defines {"NDEBUG"}
+ flags {"Optimize", "NoMinimalRebuild", "NoIncrementalLink", "NoEditAndContinue"}
+ buildoptions {"/Ox"}
+
+ if not _OPTIONS["no-suffix"] then
+ configuration {"Debug", "x32"}
+ targetsuffix ("32D")
+
+ configuration {"Debug", "x64"}
+ targetsuffix ("64D")
+
+ configuration {"Release", "x32"}
+ targetsuffix ("32")
+
+ configuration {"Release", "x64"}
+ targetsuffix ("64")
+ end
+
+ configuration("vs2017 or vs2019 or vs2022")
+ buildoptions {"/permissive-",}
+
+ if not _OPTIONS["no-embed-tommath"] then
+ project ("libtommath")
+ uuid ("47726E76-07B8-433D-A9AF-01111EB92825") -- same as in libtommath
+ language ("C")
+ kind ("StaticLib")
+ flags {"StaticRuntime", "NoPCH", }
+ targetname ("tommath")
+ flags {"Unicode", "NativeWChar", "FatalWarnings"}
+ targetdir (tgtdir .. "\\$(ProjectName)")
+ objdir (outdir .. "\\Intermediate\\$(ProjectName)")
+ --libdirs {"$(IntDir)"}
+ includedirs {"."} -- not really needed, but we try to stay true to makefile.msvc
+ defines {"WIN32_LEAN_AND_MEAN", "WINVER=0x0501", "WIN32", "_CRT_SECURE_NO_WARNINGS", "_CRT_NONSTDC_NO_DEPRECATE",}
+ buildoptions {"/Z7", "/Wall", "/wd4146", "/wd4127", "/wd4668", "/wd4710", "/wd4711", "/wd4820",}
+ -- /Z7 for a static lib includes all debug symbols inside the object files, meaning there is no need to distribute PDB _and_ .lib file
+
+ excludes
+ {
+ "Backup*.*",
+ }
+
+ files
+ {
+ tommath_dir .. "/*mp_*.c",
+ tommath_dir .. "/*.h",
+ tommath_dir .. "/*.md",
+ tommath_dir .. "/*.rst",
+ }
+
+ vpaths
+ {
+ ["Header Files/*"] = { tommath_dir .. "/**.h", },
+ ["Source Files/*"] = { tommath_dir .. "/**.c", },
+ ["*"] = { tommath_dir .. "/*.md", tommath_dir .. "/*.rst", },
+ }
+
+ configuration {"Debug"}
+ defines {"_DEBUG"}
+
+ configuration {"Release"}
+ defines {"NDEBUG"}
+ flags {"Optimize", "NoMinimalRebuild", "NoIncrementalLink", "NoEditAndContinue"}
+ buildoptions {"/Ox"}
+
+ if not _OPTIONS["no-suffix"] then
+ configuration {"Debug", "x32"}
+ targetsuffix ("32D")
+
+ configuration {"Debug", "x64"}
+ targetsuffix ("64D")
+
+ configuration {"Release", "x32"}
+ targetsuffix ("32")
+
+ configuration {"Release", "x64"}
+ targetsuffix ("64")
+ end
+
+ configuration("vs2003 or vs2005")
+ buildoptions {"/wd4242", "/wd4244",}
+
+ configuration("vs2003 or vs2005 or vs2008")
+ buildoptions {"/wd4255",}
+
+ configuration("vs2019 or vs2022")
+ buildoptions {"/wd5045",}
+
+ configuration("vs2017 or vs2019 or vs2022")
+ buildoptions {"/permissive-",}
+
+ end
+
+-- Customizations of the project output, specific to this premake4.lua
+do
+ -- Embed the property sheet
+ _G.override_vcxproj = function(prj, orig_p, indent, msg, first, ...)
+ -- Inserting the property sheet here, will allow anyone to non-invasively override project behavior later on (VS2010..)
+ if indent == 1 then
+ if msg == [[]] then
+ orig_p(indent, msg, first, ...) -- pass through original line
+ orig_p(indent, [[]])
+ orig_p(indent, [[]])
+ orig_p(indent+1, [[]])
+ orig_p(indent+1, [[]])
+ return true
+ end
+ end
+ if (indent == 2) and (msg == 'Win32Proj') then
+ orig_p(indent, msg, first, ...) -- pass through original line
+ orig_p(indent, '%s', prj.name) -- raw name, without appended .vsXX marker
+ return true
+ end
+ end
+end
+
+--[[
+ This part of the premake4.lua modifies the core premake4 behavior a little.
+
+ It does the following (in order of appearence below):
+
+ - New option --sdkver to override on modern VS
+ - New option --clang to request ClangCL toolset on modern VS
+ - New option --xp to request XP-compatible toolset on modern VS
+ - On older premake4 versions it will provide a premake.project.getbasename
+ function, furthermore two other functions get patched to make use of it
+ - premake.project.getbasename() gets overridden to insert a marker into the
+ created file name, based on the chosen action
+ Example: foobar.vcxproj becomes foobar.vs2022.vcxproj etc ...
+ The purpose of this exercise is to allow for projects/solutions of several
+ Visual Studio versions to reside in the same folder
+ - Options "dotnet" gets removed
+ - The "platform" option has some allowed values removed
+ - The "os" option has some allowed values removed
+ - The actions are trimmed to what we know can work
+]]
+
+newoption { trigger = "sdkver", value = "SDKVER", description = "Allows to override SDK version (VS2015 through VS2022)" }
+newoption { trigger = "clang", description = "Allows to use clang-cl as compiler and lld-link as linker (VS2019 and VS2022)" }
+newoption { trigger = "xp", description = "Allows to use a supported XP toolset for some VS versions" }
+
+do
+ -- This is mainly to support older premake4 builds
+ if not premake.project.getbasename then
+ print "Magic happens for old premake4 versions without premake.project.getbasename() ..."
+ -- override the function to establish the behavior we'd get after patching Premake to have premake.project.getbasename
+ premake.project.getbasename = function(prjname, pattern)
+ return pattern:gsub("%%%%", prjname)
+ end
+ -- obviously we also need to overwrite the following to generate functioning VS solution files
+ premake.vstudio.projectfile = function(prj)
+ local pattern
+ if prj.language == "C#" then
+ pattern = "%%.csproj"
+ else
+ pattern = iif(_ACTION > "vs2008", "%%.vcxproj", "%%.vcproj")
+ end
+
+ local fname = premake.project.getbasename(prj.name, pattern)
+ fname = path.join(prj.location, fname)
+ return fname
+ end
+ -- we simply overwrite the original function on older Premake versions
+ premake.project.getfilename = function(prj, pattern)
+ local fname = premake.project.getbasename(prj.name, pattern)
+ fname = path.join(prj.location, fname)
+ return path.getrelative(os.getcwd(), fname)
+ end
+ end
+ -- Make UUID generation for filters deterministic
+ if os.str2uuid ~= nil then
+ local vc2010 = premake.vstudio.vc2010
+ vc2010.filteridgroup = function(prj)
+ local filters = { }
+ local filterfound = false
+
+ for file in premake.project.eachfile(prj) do
+ -- split the path into its component parts
+ local folders = string.explode(file.vpath, "/", true)
+ local path = ""
+ for i = 1, #folders - 1 do
+ -- element is only written if there *are* filters
+ if not filterfound then
+ filterfound = true
+ _p(1,"")
+ end
+
+ path = path .. folders[i]
+
+ -- have I seen this path before?
+ if not filters[path] then
+ local seed = path .. (prj.uuid or "")
+ local deterministic_uuid = os.str2uuid(seed)
+ filters[path] = true
+ _p(2, '', path)
+ _p(3, "{%s}", deterministic_uuid)
+ _p(2, "")
+ end
+
+ -- prepare for the next subfolder
+ path = path .. "\\"
+ end
+ end
+
+ if filterfound then
+ _p(1,"")
+ end
+ end
+ end
+ -- Name the project files after their VS version
+ local orig_getbasename = premake.project.getbasename
+ premake.project.getbasename = function(prjname, pattern)
+ -- The below is used to insert the .vs(8|9|10|11|12|14|15|16|17) into the file names for projects and solutions
+ if _ACTION then
+ name_map = {vs2005 = "vs8", vs2008 = "vs9", vs2010 = "vs10", vs2012 = "vs11", vs2013 = "vs12", vs2015 = "vs14", vs2017 = "vs15", vs2019 = "vs16", vs2022 = "vs17"}
+ if name_map[_ACTION] then
+ pattern = pattern:gsub("%%%%", "%%%%." .. name_map[_ACTION])
+ else
+ pattern = pattern:gsub("%%%%", "%%%%." .. _ACTION)
+ end
+ end
+ return orig_getbasename(prjname, pattern)
+ end
+ -- Premake4 sets the PDB file name for the compiler's PDB to the default
+ -- value used by the linker's PDB. This causes error C1052 on VS2017. Fix it.
+ -- But this also fixes up certain other areas of the generated project. The idea
+ -- here is to catch the original _p() invocations, evaluate the arguments and
+ -- then act based on those, using orig_p() as a standin during a call to the
+ -- underlying premake.vs2010_vcxproj() function ;-)
+ local orig_premake_vs2010_vcxproj = premake.vs2010_vcxproj
+ premake.vs2010_vcxproj = function(prj)
+ -- The whole stunt below is necessary in order to modify the resource_compile()
+ -- output. Given it's a local function we have to go through hoops.
+ local orig_p = _G._p
+ local besilent = false
+ -- We patch the global _p() function
+ _G._p = function(indent, msg, first, ...)
+ -- Look for non-empty messages and narrow it down by the indent values
+ if msg ~= nil then
+ -- Allow this logic to be hooked and the hook to preempt any action hardcoded below
+ if (_G.override_vcxproj ~= nil) and (type(_G.override_vcxproj) == 'function') then
+ if _G.override_vcxproj(prj, orig_p, indent, msg, first, ...) then
+ return -- suppress further output
+ end
+ end
+ if msg:match("[^<]+") then
+ return -- we want to suppress these
+ end
+ if indent == 2 then
+ if msg == "%s" then
+ local sdkmap = {vs2015 = "8.1", vs2017 = "10.0.17763.0", vs2019 = "10.0", vs2022 = "10.0"}
+ if (not _ACTION) or (not sdkmap[_ACTION]) then -- should not happen, but tread carefully anyway
+ orig_p(indent, msg, first, ...) -- what was originally supposed to be output
+ return
+ end
+ local sdkver = _OPTIONS["sdkver"] or sdkmap[_ACTION]
+ orig_p(indent, msg, first, ...) -- what was originally supposed to be output
+ orig_p(indent, "%s", sdkver)
+ return
+ end
+ if msg == "%s" then
+ if (_OPTIONS["clang"] ~= nil) and (_ACTION == "vs2017") then
+ if _OPTIONS["xp"] ~= nil then
+ print "WARNING: The --clang option takes precedence over --xp, therefore picking v141_clang_c2 toolset."
+ end
+ print "WARNING: If you are used to Clang support from VS2019 and newer, be sure to review your choice. It's not the same on older VS versions."
+ orig_p(indent, msg, "v141_clang_c2")
+ return
+ elseif (_OPTIONS["clang"] ~= nil) and (_ACTION >= "vs2019") then
+ if _OPTIONS["xp"] ~= nil then
+ print "WARNING: The --clang option takes precedence over --xp, therefore picking ClangCL toolset."
+ end
+ orig_p(indent, msg, "ClangCL")
+ return
+ elseif _OPTIONS["xp"] ~= nil then
+ local toolsets = { vs2012 = "v110", vs2013 = "v120", vs2015 = "v140", vs2017 = "v141", vs2019 = "v142", vs2022 = "v143" }
+ local toolset = toolsets[_ACTION]
+ if toolset then
+ if _OPTIONS["xp"] and toolset >= "v141" then
+ toolset = "v141" -- everything falls back to the VS2017 XP toolset for more recent VS
+ end
+ orig_p(indent,"%s_xp", toolset)
+ return
+ end
+ end
+ end
+ elseif indent == 3 then
+ -- This is what vanilla VS would output it as, so let's try to align with that
+ if msg == "" then
+ orig_p(indent, "")
+ orig_p(indent, "")
+ return
+ end
+ end
+ end
+ if not besilent then -- should we be silent (i.e. suppress default output)?
+ orig_p(indent, msg, first, ...)
+ end
+ end
+ orig_premake_vs2010_vcxproj(prj)
+ _G._p = orig_p -- restore in any case
+ end
+ -- ... same as above but for VS200x this time
+ local function wrap_remove_pdb_attribute(origfunc)
+ local fct = function(cfg)
+ local old_captured = io.captured -- save io.captured state
+ io.capture() -- this sets io.captured = ""
+ origfunc(cfg)
+ local captured = io.endcapture()
+ assert(captured ~= nil)
+ captured = captured:gsub('%s+ProgramDataBaseFileName=\"[^"]+\"', "")
+ if old_captured ~= nil then
+ io.captured = old_captured .. captured -- restore outer captured state, if any
+ else
+ io.write(captured)
+ end
+ end
+ return fct
+ end
+ premake.vstudio.vc200x.VCLinkerTool = wrap_remove_pdb_attribute(premake.vstudio.vc200x.VCLinkerTool)
+ premake.vstudio.vc200x.toolmap.VCLinkerTool = premake.vstudio.vc200x.VCLinkerTool -- this is important as well
+ premake.vstudio.vc200x.VCCLCompilerTool = wrap_remove_pdb_attribute(premake.vstudio.vc200x.VCCLCompilerTool)
+ premake.vstudio.vc200x.toolmap.VCCLCompilerTool = premake.vstudio.vc200x.VCCLCompilerTool -- this is important as well
+ -- Override the object directory paths ... don't make them "unique" inside premake4
+ local orig_gettarget = premake.gettarget
+ premake.gettarget = function(cfg, direction, pathstyle, namestyle, system)
+ local r = orig_gettarget(cfg, direction, pathstyle, namestyle, system)
+ if (cfg.objectsdir) and (cfg.objdir) then
+ cfg.objectsdir = cfg.objdir
+ end
+ return r
+ end
+ -- Silently suppress generation of the .user files ...
+ local orig_generate = premake.generate
+ premake.generate = function(obj, filename, callback)
+ if filename:find(".vcproj.user") or filename:find(".vcxproj.user") then
+ return
+ end
+ orig_generate(obj, filename, callback)
+ end
+ -- Fix up premake.getlinks() to not do stupid stuff with object files we pass
+ local orig_premake_getlinks = premake.getlinks
+ premake.getlinks = function(cfg, kind, part)
+ local origret = orig_premake_getlinks(cfg, kind, part)
+ local ret = {}
+ for k,v in ipairs(origret) do
+ local dep = v:gsub(".obj.lib", ".obj")
+ dep = dep:gsub(".lib.lib", ".lib")
+ table.insert(ret, dep)
+ end
+ return ret
+ end
+
+ -- Remove an option altogether or some otherwise accepted values for that option
+ local function remove_allowed_optionvalues(option, values_toremove)
+ if premake.option.list[option] ~= nil then
+ if values_toremove == nil then
+ premake.option.list[option] = nil
+ return
+ end
+ if premake.option.list.platform["allowed"] ~= nil then
+ local allowed = premake.option.list[option].allowed
+ for i = #allowed, 1, -1 do
+ if values_toremove[allowed[i][1]] then
+ table.remove(allowed, i)
+ end
+ end
+ end
+ end
+ end
+
+ local function remove_action(action)
+ if premake.action.list[action] ~= nil then
+ premake.action.list[action] = nil
+ end
+ end
+
+ -- Remove some unwanted/outdated options
+ remove_allowed_optionvalues("dotnet")
+ remove_allowed_optionvalues("platform", { universal = 0, universal32 = 0, universal64 = 0, ps3 = 0, xbox360 = 0, })
+ remove_allowed_optionvalues("os", { haiku = 0, solaris = 0, })
+ -- ... and actions (mainly because they are untested)
+ for k,v in pairs({codeblocks = 0, codelite = 0, xcode3 = 0, xcode4 = 0, vs2002 = 0}) do
+ remove_action(k)
+ end
+end