--!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, Xmake Open Source Community. -- -- @author ruki -- @file vs200x_vcproj.lua -- -- imports import("core.tool.linker") import("core.tool.compiler") import("core.project.config") import("vsfile") -- make compiling flags function _make_compflags(sourcefile, target, vcprojdir) -- make the compiling flags local compflags = compiler.compflags(sourcefile, {target = target}) -- replace -Idir or /Idir, -Fdsymbol.pdb or /Fdsymbol.pdb local flags = {} for _, flag in ipairs(compflags) do local flag = flag -- replace -Idir or /Idir flag = flag:gsub("[%-|/]I(.*)", function (dir) dir = path.translate(dir:trim()) if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcprojdir) end return "/I" .. dir end) -- replace -Fdsymbol.pdb or /Fdsymbol.pdb flag = flag:gsub("[%-|/]Fd(.*)", function (dir) dir = path.translate(dir:trim()) if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcprojdir) end return "/Fd" .. dir end) -- save flag table.insert(flags, flag) end -- make flags string flags = os.args(flags) -- replace " => " flags = flags:gsub("\"", """) -- ok? return flags end -- make linking flags function _make_linkflags(target, vcprojdir) -- make the linking flags local linkflags = linker.linkflags(target:kind(), target:sourcekinds(), {target = target}) -- replace -libpath:dir or /libpath:dir, -pdb:symbol.pdb or /pdb:symbol.pdb local flags = {} for _, flag in ipairs(linkflags) do local flag = flag -- replace -libpath:dir or /libpath:dir flag = flag:gsub("[%-|/]libpath:(.*)", function (dir) dir = path.translate(dir:trim()) if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcprojdir) end return "/libpath:" .. dir end) -- replace -pdb:symbol.pdb or /pdb:symbol.pdb flag = flag:gsub("[%-|/]pdb:(.*)", function (dir) dir = path.translate(dir:trim()) if not path.is_absolute(dir) then dir = path.relative(path.absolute(dir), vcprojdir) end return "/pdb:" .. dir end) -- save flag table.insert(flags, flag) end -- make flags string flags = os.args(flags) -- replace " => " flags = flags:gsub("\"", """) -- ok? return flags end -- make header function _make_header(vcprojfile, vsinfo, target) -- the target name local targetname = target:name() -- make header vcprojfile:print("") vcprojfile:enter("") end -- make tailer function _make_tailer(vcprojfile, vsinfo, target) vcprojfile:leave("") end -- make platforms function _make_platforms(vcprojfile, vsinfo, target) -- add Win32 platform vcprojfile:enter("") vcprojfile:enter("") vcprojfile:leave("") end -- make toolfiles function _make_toolfiles(vcprojfile, vsinfo, target) -- empty toolfiles vcprojfile:enter("") vcprojfile:leave("") end -- make VCCLCompilerTool -- -- e.g. -- -- function _make_VCCLCompilerTool(vcprojfile, vsinfo, target, compflags) vcprojfile:enter("") end -- make VCLinkerTool -- -- e.g. -- function _make_VCLinkerTool(vcprojfile, vsinfo, target, vcprojdir) -- need not linker? local kind = target:kind() if kind ~= "binary" and kind ~= "shared" then vcprojfile:enter("") return end -- generate debug infomation? local debug = false for _, symbol in ipairs(target:get("symbols")) do if symbol == "debug" then debug = true break end end -- subsystem, console: 1, windows: 2 local subsystem = 1 local flags = _make_linkflags(target, vcprojdir) if flags:lower():find("[%-/]subsystem:windows") then subsystem = 2 end -- make it vcprojfile:enter("") end -- make configurations function _make_configurations(vcprojfile, vsinfo, target, vcprojdir) -- init configuration type local configuration_types = { binary = 1 , shared = 2 , static = 4 } -- save compiler flags local compflags=nil for _, sourcebatch in pairs(target:sourcebatches()) do local sourcekind = sourcebatch.sourcekind if sourcekind then for _, sourcefile in ipairs(sourcebatch.sourcefiles) do local flags = compiler.compflags(sourcefile, {target = target}) if sourcekind == "cc" or sourcekind == "cxx" then compflags = flags break end end end if compflags then break end end -- use mfc? not used: 0, static: 1, shared: 2 local usemfc = 0 if target:rule("win.sdk.mfc.shared_app") or target:rule("win.sdk.mfc.shared") then usemfc = 2 elseif target:rule("win.sdk.mfc.static_app") or target:rule("win.sdk.mfc.static") then usemfc = 1 end -- set unicode local unicode = false for _, flag in ipairs(compflags) do if flag:find("[%-|/]DUNICODE") then unicode = true break end end -- enter configurations vcprojfile:enter("") -- make configuration for the current mode vcprojfile:enter("") -- make VCPreBuildEventTool vcprojfile:enter("") -- make VCCustomBuildTool vcprojfile:enter("") -- make VCXMLDataGeneratorTool vcprojfile:enter("") -- make VCWebServiceProxyGeneratorTool vcprojfile:enter("") -- make VCMIDLTool vcprojfile:enter("") -- make VCCLCompilerTool _make_VCCLCompilerTool(vcprojfile, vsinfo, target, compflags) -- make VCManagedResourceCompilerTool vcprojfile:enter("") -- make VCResourceCompilerTool vcprojfile:enter("") -- make VCPreLinkEventTool vcprojfile:enter("") -- make VCLinkerTool _make_VCLinkerTool(vcprojfile, vsinfo, target, vcprojdir) -- make VCALinkTool vcprojfile:enter("") -- make VCManifestTool vcprojfile:enter("") -- make VCXDCMakeTool vcprojfile:enter("") -- make VCBscMakeTool vcprojfile:enter("") -- make VCFxCopTool vcprojfile:enter("") -- make VCAppVerifierTool vcprojfile:enter("") -- make VCPostBuildEventTool vcprojfile:enter("") -- leave configuration vcprojfile:leave("") -- leave configurations vcprojfile:leave("") end -- make references function _make_references(vcprojfile, vsinfo, target) vcprojfile:enter("") vcprojfile:leave("") end -- make cxfile -- -- e.g. -- -- -- -- -- function _make_cxfile(vcprojfile, vsinfo, target, sourcefile, objectfile, vcprojdir) -- get the target key local key = target:cachekey() -- make flags cache _g.flags = _g.flags or {} -- make flags local flags = _g.flags[key] or _make_compflags(sourcefile, target, vcprojdir) _g.flags[key] = flags -- enter file vcprojfile:enter("") -- add file configuration vcprojfile:enter("") -- add compiling options vcprojfile:enter("") vcprojfile:leave("") -- leave file vcprojfile:leave("") end -- make rcfile -- -- e.g. -- -- -- -- -- function _make_rcfile(vcprojfile, vsinfo, target, sourcefile, objectfile, vcprojdir) -- enter file vcprojfile:enter("") -- add file configuration vcprojfile:enter("") -- add compiling options vcprojfile:enter("") vcprojfile:leave("") -- leave file vcprojfile:leave("") end -- make files -- -- e.g. -- -- -- -- -- -- -- -- -- -- -- -- -- function _make_files(vcprojfile, vsinfo, target, vcprojdir) -- enter files vcprojfile:enter("") local sourcebatches = target:sourcebatches() -- c/cxx files vcprojfile:enter("") for _, sourcebatch in pairs(sourcebatches) do local sourcekind = sourcebatch.sourcekind if sourcekind ~= "mrc" then local objectfiles = sourcebatch.objectfiles for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do _make_cxfile(vcprojfile, vsinfo, target, sourcefile, objectfiles[idx], vcprojdir) end end end -- leave c/cxx files vcprojfile:leave("") -- *.rc files vcprojfile:enter("") for _, sourcebatch in pairs(sourcebatches) do local sourcekind = sourcebatch.sourcekind if sourcekind == "mrc" then local objectfiles = sourcebatch.objectfiles for idx, sourcefile in ipairs(sourcebatch.sourcefiles) do _make_rcfile(vcprojfile, vsinfo, target, sourcefile, objectfiles[idx], vcprojdir) end end end -- leave *.rc files vcprojfile:leave("") vcprojfile:leave("") end -- make globals function _make_globals(vcprojfile, vsinfo, target) vcprojfile:enter("") vcprojfile:leave("") end -- make vcproj function make(vsinfo, target) -- the target name local targetname = target:name() -- the vcproj directory local vcprojdir = path.join(vsinfo.solution_dir, targetname) -- open vcproj file local vcprojfile = vsfile.open(path.join(vcprojdir, targetname .. ".vcproj"), "w") -- init indent character vsfile.indentchar('\t') -- make header _make_header(vcprojfile, vsinfo, target) -- make platforms _make_platforms(vcprojfile, vsinfo, target) -- make toolfiles _make_toolfiles(vcprojfile, vsinfo, target) -- make configurations _make_configurations(vcprojfile, vsinfo, target, vcprojdir) -- make references _make_references(vcprojfile, vsinfo, target) -- make files _make_files(vcprojfile, vsinfo, target, vcprojdir) -- make globals _make_globals(vcprojfile, vsinfo, target) -- make tailer _make_tailer(vcprojfile, vsinfo, target) -- exit solution file vcprojfile:close() end