--!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