--!The Make-like Build Utility based on Lua -- -- XMake is free software; you can redistribute it and/or modify -- it under the terms of the GNU Lesser General Public License as published by -- the Free Software Foundation; either version 2.1 of the License, or -- (at your option) any later version. -- -- XMake is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public License -- along with XMake; -- If not, see http://www.gnu.org/licenses/ -- -- Copyright (C) 2015 - 2016, ruki All rights reserved. -- -- @author ruki -- @file vs201x_vcxproj.lua -- -- imports import("core.tool.linker") import("core.tool.compiler") import("core.project.config") import("vsfile") -- make compiling flags function _make_compflags(sourcefile, target, vcxprojdir) -- make the compiling flags local _, compflags = compiler.compflags(sourcefile, target) -- replace -Idir or /Idir, -Fdsymbol.pdb or /Fdsymbol.pdb local flags = {} for _, flag in ipairs(compflags) do -- replace -Idir or /Idir flag = flag:gsub("[%-|/]I(.*)", function (dir) dir = dir:trim() if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcxprojdir) end return "/I" .. dir end) -- replace -Fdsymbol.pdb or /Fdsymbol.pdb flag = flag:gsub("[%-|/]Fd(.*)", function (dir) dir = dir:trim() if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcxprojdir) end return "/Fd" .. dir end) -- save flag table.insert(flags, flag) end -- concat flags flags = table.concat(flags, " "):trim() -- ok? return flags end -- make linking flags function _make_linkflags(target, vcxprojdir) -- make the linking flags local _, linkflags = linker.linkflags(target) -- replace -libpath:dir or /libpath:dir, -pdb:symbol.pdb or /pdb:symbol.pdb local flags = {} for _, flag in ipairs(linkflags) do -- replace -libpath:dir or /libpath:dir flag = flag:gsub("[%-|/]libpath:(.*)", function (dir) dir = dir:trim() if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcxprojdir) end return "/libpath:" .. dir end) -- replace -pdb:symbol.pdb or /pdb:symbol.pdb flag = flag:gsub("[%-|/]pdb:(.*)", function (dir) dir = dir:trim() if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcxprojdir) end return "/pdb:" .. dir end) -- save flag table.insert(flags, flag) end -- concat flags flags = table.concat(flags, " "):trim() -- ok? return flags end -- make header function _make_header(vcxprojfile, vsinfo, target) -- the versions local versions = { vs2010 = '4' , vs2012 = '4' , vs2013 = '12' , vs2015 = '14' } -- make header vcxprojfile:print("") vcxprojfile:enter("", assert(versions["vs" .. vsinfo.vstudio_version])) end -- make tailer function _make_tailer(vcxprojfile, vsinfo, target) vcxprojfile:print("") vcxprojfile:enter("") vcxprojfile:leave("") vcxprojfile:leave("") end -- make Configurations function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) -- the target name local targetname = target:name() -- init configuration type local configuration_types = { binary = "Application" , shared = "DynamicLibrary" , static = "StaticLibrary" } -- the versions local versions = { vs2010 = '10' , vs2012 = '11' , vs2013 = '12' , vs2015 = '14' } -- make ProjectConfigurations vcxprojfile:enter("") vcxprojfile:enter("") vcxprojfile:print("$(mode)") vcxprojfile:print("Win32") vcxprojfile:leave("") vcxprojfile:leave("") -- make Globals vcxprojfile:enter("") vcxprojfile:print("{%s}", os.uuid(targetname)) vcxprojfile:print("%s", targetname) vcxprojfile:leave("") -- import Microsoft.Cpp.Default.props vcxprojfile:print("") -- make Configuration vcxprojfile:enter("") vcxprojfile:print("%s", assert(configuration_types[target:get("kind")])) vcxprojfile:print("v%s0", assert(versions["vs" .. vsinfo.vstudio_version])) vcxprojfile:print("MultiByte") vcxprojfile:leave("") -- import Microsoft.Cpp.props vcxprojfile:print("") -- make ExtensionSettings vcxprojfile:enter("") vcxprojfile:leave("") -- make PropertySheets vcxprojfile:enter("") vcxprojfile:print("") vcxprojfile:leave("") -- make UserMacros vcxprojfile:print("") -- make OutputDirectory and IntermediateDirectory vcxprojfile:enter("") vcxprojfile:print("%s\\", path.relative(path.absolute(config.get("buildir")), vcxprojdir)) vcxprojfile:print("%$(Configuration)\\") if target:get("kind") == "binary" then vcxprojfile:print("true") end vcxprojfile:leave("") end -- make ItemDefinitionGroup function _make_item_define_group(vcxprojfile, vsinfo, target, vcxprojdir) -- enter ItemDefinitionGroup vcxprojfile:enter("") -- for linker? if target:get("kind") == "binary" then vcxprojfile:enter("") -- make AdditionalOptions vcxprojfile:print("%s %%(AdditionalOptions)", _make_linkflags(target, vcxprojdir)) -- generate debug infomation? local debug = false for _, symbol in ipairs(target:get("symbols")) do if symbol == "debug" then debug = true break end end vcxprojfile:print("%s", tostring(debug)) -- make SubSystem vcxprojfile:print("Console") -- make TargetMachine vcxprojfile:print("%s", ifelse(config.arch() == "x64", "MachineX64", "MachineX86")) vcxprojfile:leave("") end -- for compiler? vcxprojfile:enter("") vcxprojfile:print("Disabled") -- disable optimization default vcxprojfile:print("") -- disable pdb file default vcxprojfile:leave("") -- leave ItemDefinitionGroup vcxprojfile:leave("") end -- make file function _make_file(vcxprojfile, vsinfo, target, sourcefile, objectfile, vcxprojdir) -- get the target key local key = tostring(target) -- make flags cache _g.flags = _g.flags or {} -- make flags local flags = _g.flags[key] or _make_compflags(sourcefile, target, vcxprojdir) _g.flags[key] = flags -- add file vcxprojfile:enter("", path.relative(path.absolute(sourcefile), vcxprojdir)) vcxprojfile:print("%s %%(AdditionalOptions)", flags) vcxprojfile:print("%s", path.relative(path.absolute(objectfile), vcxprojdir)) -- complie as c++ if exists flag: /TP if flags:find("[%-|/]TP") then vcxprojfile:print("CompileAsCpp") end vcxprojfile:leave("") end function _make_header_file(vcxprojfile, includefile, vcxprojdir) vcxprojfile:print("", path.relative(path.absolute(includefile), vcxprojdir)) end -- make source code list function _make_source_code_list(vcxprojfile, vsinfo, target, vcxprojdir) -- enter ItemGroup vcxprojfile:enter("") -- add files local objectfiles = target:objectfiles() for idx, sourcefile in ipairs(target:sourcefiles()) do _make_file(vcxprojfile, vsinfo, target, sourcefile, objectfiles[idx], vcxprojdir) end vcxprojfile:leave("") -- enter header group vcxprojfile:enter("") -- add headers for _, includefile in ipairs(target:headerfiles()) do _make_header_file(vcxprojfile, includefile, vcxprojdir) end vcxprojfile:leave("") end -- make vcxproj function make(vsinfo, target) -- the target name local targetname = target:name() -- the vcxproj directory local vcxprojdir = path.join(vsinfo.solution_dir, targetname) -- open vcxproj file local vcxprojfile = vsfile.open(path.join(vcxprojdir, targetname .. ".vcxproj"), "w") -- init indent character vsfile.indentchar(' ') -- make header _make_header(vcxprojfile, vsinfo, target) -- make Configurations _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) -- make ItemDefinitionGroup _make_item_define_group(vcxprojfile, vsinfo, target, vcxprojdir) -- make source code list _make_source_code_list(vcxprojfile, vsinfo, target, vcxprojdir) -- make tailer _make_tailer(vcxprojfile, vsinfo, target) -- exit solution file vcxprojfile:close() end