diff options
| author | Jérôme Leclercq <[email protected]> | 2021-12-22 20:56:39 +0100 |
|---|---|---|
| committer | Jérôme Leclercq <[email protected]> | 2021-12-22 20:56:39 +0100 |
| commit | 01b29068ec1effab05be538ed9df3e05727ae181 (patch) | |
| tree | e03fe3f0cc26ca2de3547e1ee8adf5e1cfa34f3b | |
| parent | 9d5658ade35f41bb2c8a348e4d835c52eb33cf5d (diff) | |
projects/vstudio: add support for runenvs
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x.lua | 104 | ||||
| -rw-r--r-- | xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua | 57 |
2 files changed, 131 insertions, 30 deletions
diff --git a/xmake/plugins/project/vstudio/impl/vs201x.lua b/xmake/plugins/project/vstudio/impl/vs201x.lua index bf76b13dc..759789fda 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x.lua @@ -33,10 +33,69 @@ import("vs201x_vcxproj_filters") import("core.cache.memcache") import("core.cache.localcache") import("private.action.require.install", {alias = "install_requires"}) +import("private.action.run.make_runenvs") import("actions.config.configfiles", {alias = "generate_configfiles", rootdir = os.programdir()}) import("actions.config.configheader", {alias = "generate_configheader", rootdir = os.programdir()}) import("private.utils.batchcmds") +-- escape special chars in msbuild file +function _escape(str) + if not str then + return nil + end + + local map = + { + ["%"] = "%25" -- Referencing metadata + , ["$"] = "%24" -- Referencing properties + , ["@"] = "%40" -- Referencing item lists + , ["'"] = "%27" -- Conditions and other expressions + , [";"] = "%3B" -- List separator + , ["?"] = "%3F" -- Wildcard character for file names in Include and Exclude attributes + , ["*"] = "%2A" -- Wildcard character for use in file names in Include and Exclude attributes + -- html entities + , ["\""] = """ + , ["<"] = "<" + , [">"] = ">" + , ["&"] = "&" + } + + return (string.gsub(str, "[%%%$@';%?%*\"<>&]", function (c) return assert(map[c]) end)) +end + +function _make_dirs(dir, vcxprojdir) + if dir == nil then + return "" + end + if type(dir) == "string" then + dir = path.translate(dir) + if dir == "" then + return "" + end + if path.is_absolute(dir) then + print("absolute") + print(dir) + print("projectdir", project.directory()) + if dir:startswith(project.directory()) then + print("relative to ", vcxprojdir) + print(dir) + return _escape(path.relative(dir, vcxprojdir)) + end + return _escape(dir) + else + print("relative") + print(dir) + return _escape(path.relative(path.absolute(dir), vcxprojdir)) + end + end + local r = {} + for k, v in ipairs(dir) do + r[k] = _make_dirs(v, vcxprojdir) + end + r = table.unique(r) + return path.joinenv(r) +end + -- clear cache configuration function _clear_cacheconf() config.clear() @@ -180,7 +239,7 @@ function _make_custom_commands(target) end -- make target info -function _make_targetinfo(mode, arch, target) +function _make_targetinfo(mode, arch, target, vcxprojdir) -- init target info local targetinfo = { mode = mode, arch = (arch == "x86" and "Win32" or "x64") } @@ -246,6 +305,44 @@ function _make_targetinfo(mode, arch, target) -- save execution dir (when executed from VS) targetinfo.rundir = target:rundir() + -- save runenvs + local runenvs = {} + local addrunenvs, setrunenvs = make_runenvs(target) + for k, v in pairs(target:pkgenvs()) do + addrunenvs = addrunenvs or {} + addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v)) + end + for _, dep in ipairs(target:orderdeps()) do + for k, v in pairs(dep:pkgenvs()) do + addrunenvs = addrunenvs or {} + addrunenvs[k] = table.join(table.wrap(addrunenvs[k]), path.splitenv(v)) + end + end + for k, v in pairs(addrunenvs) do + if k:upper() == "PATH" then + runenvs[k] = format("%s;$([System.Environment]::GetEnvironmentVariable('%s'))", _make_dirs(v, vcxprojdir), k) + else + runenvs[k] = format("%s;$([System.Environment]::GetEnvironmentVariable('%s'))", path.joinenv(v), k) + end + end + for k, v in pairs(setrunenvs) do + if #v == 1 then + v = v[1] + if path.is_absolute(v) and v:startswith(project.directory()) then + runenvs[k] = _make_dirs(v, vcxprojdir) + else + runenvs[k] = v[1] + end + else + runenvs[k] = path.joinenv(v) + end + end + local runenvstr = {} + for k, v in pairs(runenvs) do + table.insert(runenvstr, k .. "=" .. v) + end + targetinfo.runenvs = table.concat(runenvstr, "\n") + -- use mfc? save the mfc runtime kind if target:rule("win.sdk.mfc.shared_app") or target:rule("win.sdk.mfc.shared") then targetinfo.usemfc = "Dynamic" @@ -462,6 +559,9 @@ function make(outputdir, vsinfo) -- make target with the given mode and arch targets[targetname] = targets[targetname] or {} local _target = targets[targetname] + + -- the vcxproj directory + _target.project_dir = path.join(vsinfo.solution_dir, targetname) -- save c/c++ precompiled header _target.pcheader = target:pcheaderfile("c") -- header.h @@ -472,7 +572,7 @@ function make(outputdir, vsinfo) _target.kind = target:kind() _target.scriptdir = target:scriptdir() _target.info = _target.info or {} - table.insert(_target.info, _make_targetinfo(mode, arch, target)) + table.insert(_target.info, _make_targetinfo(mode, arch, target, _target.project_dir)) -- save all sourcefiles and headerfiles _target.sourcefiles = table.unique(table.join(_target.sourcefiles or {}, (target:sourcefiles()))) diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua index 154e0763b..0d3d06da5 100644 --- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua +++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua @@ -166,7 +166,7 @@ function _make_tailer(vcxprojfile, vsinfo) end -- make Configurations -function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) +function _make_configurations(vcxprojfile, vsinfo, target) -- the target name local targetname = target.name @@ -233,8 +233,8 @@ function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) -- make OutputDirectory and IntermediateDirectory for _, targetinfo in ipairs(target.info) do vcxprojfile:enter("<PropertyGroup Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">", targetinfo.mode, targetinfo.arch) - vcxprojfile:print("<OutDir>%s\\</OutDir>", _make_dirs(targetinfo.targetdir, vcxprojdir)) - vcxprojfile:print("<IntDir>%s\\</IntDir>", _make_dirs(targetinfo.objectdir, vcxprojdir)) + vcxprojfile:print("<OutDir>%s\\</OutDir>", _make_dirs(targetinfo.targetdir, target.project_dir)) + vcxprojfile:print("<IntDir>%s\\</IntDir>", _make_dirs(targetinfo.objectdir, target.project_dir)) vcxprojfile:print("<TargetName>%s</TargetName>", path.basename(targetinfo.targetfile)) vcxprojfile:print("<TargetExt>%s</TargetExt>", path.extension(targetinfo.targetfile)) @@ -247,7 +247,8 @@ function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) -- make Debugger for _, targetinfo in ipairs(target.info) do vcxprojfile:enter("<PropertyGroup Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\" Label=\"Debugger\">", targetinfo.mode, targetinfo.arch) - vcxprojfile:print("<LocalDebuggerWorkingDirectory>%s</LocalDebuggerWorkingDirectory>", _make_dirs(targetinfo.rundir, vcxprojdir)) + vcxprojfile:print("<LocalDebuggerWorkingDirectory>%s</LocalDebuggerWorkingDirectory>", _make_dirs(targetinfo.rundir, target.project_dir)) + vcxprojfile:print("<LocalDebuggerEnvironment>%s;$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>", targetinfo.runenvs) vcxprojfile:leave("</PropertyGroup>") end end @@ -530,7 +531,7 @@ function _make_common_item(vcxprojfile, vsinfo, target, targetinfo, vcxprojdir) end -- make common items -function _make_common_items(vcxprojfile, vsinfo, target, vcxprojdir) +function _make_common_items(vcxprojfile, vsinfo, target) -- for each mode and arch for _, targetinfo in ipairs(target.info) do @@ -546,7 +547,7 @@ function _make_common_items(vcxprojfile, vsinfo, target, vcxprojdir) for _, sourcefile in ipairs(sourcebatch.sourcefiles) do -- make compiler flags - local flags = _make_compflags(sourcefile, targetinfo, vcxprojdir) + local flags = _make_compflags(sourcefile, targetinfo, target.project_dir) -- no common flags for asm if sourcekind ~= "as" then @@ -591,7 +592,7 @@ function _make_common_items(vcxprojfile, vsinfo, target, vcxprojdir) targetinfo.sourceflags = sourceflags -- make common item - _make_common_item(vcxprojfile, vsinfo, target, targetinfo, vcxprojdir) + _make_common_item(vcxprojfile, vsinfo, target, targetinfo, target.project_dir) end end @@ -601,7 +602,7 @@ function _make_header_file(vcxprojfile, includefile, vcxprojdir) end -- make source file for all modes -function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourceinfo, vcxprojdir) +function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourceinfo) -- get object file and source kind local sourcekind = nil @@ -612,7 +613,7 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc -- enter it local nodename = (sourcekind == "as" and "CustomBuild" or (sourcekind == "mrc" and "ResourceCompile" or "ClCompile")) - sourcefile = path.relative(path.absolute(sourcefile), vcxprojdir) + sourcefile = path.relative(path.absolute(sourcefile), target.project_dir) vcxprojfile:enter("<%s Include=\"%s\">", nodename, sourcefile) -- for *.asm files @@ -620,8 +621,8 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc vcxprojfile:print("<ExcludedFromBuild>false</ExcludedFromBuild>") vcxprojfile:print("<FileType>Document</FileType>") for _, info in ipairs(sourceinfo) do - local objectfile = path.relative(path.absolute(info.objectfile), vcxprojdir) - local compcmd = _make_compcmd(info.compargv, sourcefile, objectfile, vcxprojdir) + local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir) + local compcmd = _make_compcmd(info.compargv, sourcefile, objectfile, target.project_dir) vcxprojfile:print("<Outputs Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s\'\">%s</Outputs>", info.mode .. '|' .. info.arch, objectfile) vcxprojfile:print("<Command Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s\'\">%s</Command>", info.mode .. '|' .. info.arch, compcmd) end @@ -630,7 +631,7 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc -- for *.rc files elseif sourcekind == "mrc" then for _, info in ipairs(sourceinfo) do - local objectfile = path.relative(path.absolute(info.objectfile), vcxprojdir) + local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir) vcxprojfile:print("<ResourceOutputFileName Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</ResourceOutputFileName>", info.mode, info.arch, objectfile) end @@ -717,10 +718,10 @@ function _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourc end -- make source file for specific modes -function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sourceinfo, vcxprojdir) +function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sourceinfo) -- add source file - sourcefile = path.relative(path.absolute(sourcefile), vcxprojdir) + sourcefile = path.relative(path.absolute(sourcefile), target.project_dir) for _, info in ipairs(sourceinfo) do -- enter it @@ -728,9 +729,9 @@ function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sour vcxprojfile:enter("<%s Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\" Include=\"%s\">", nodename, info.mode, info.arch, sourcefile) -- for *.asm files - local objectfile = path.relative(path.absolute(info.objectfile), vcxprojdir) + local objectfile = path.relative(path.absolute(info.objectfile), target.project_dir) if info.sourcekind == "as" then - local compcmd = _make_compcmd(info.compargv, sourcefile, objectfile, vcxprojdir) + local compcmd = _make_compcmd(info.compargv, sourcefile, objectfile, target.project_dir) vcxprojfile:print("<ExcludedFromBuild>false</ExcludedFromBuild>") vcxprojfile:print("<FileType>Document</FileType>") vcxprojfile:print("<Outputs>%s</Outputs>", objectfile) @@ -757,12 +758,12 @@ function _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sour end -- make source file for precompiled header -function _make_source_file_forpch(vcxprojfile, vsinfo, target, vcxprojdir) +function _make_source_file_forpch(vcxprojfile, vsinfo, target) -- add precompiled source file local pcheader = target.pcxxheader or target.pcheader if pcheader then - local sourcefile = path.relative(path.absolute(pcheader), vcxprojdir) + local sourcefile = path.relative(path.absolute(pcheader), target.project_dir) vcxprojfile:enter("<ClCompile Include=\"%s\">", sourcefile) vcxprojfile:print("<PrecompiledHeader>Create</PrecompiledHeader>") vcxprojfile:print("<PrecompiledHeaderFile></PrecompiledHeaderFile>") @@ -776,7 +777,7 @@ function _make_source_file_forpch(vcxprojfile, vsinfo, target, vcxprojdir) -- add object file local pcoutputfile = info.pcxxoutputfile or info.pcoutputfile if pcoutputfile then - local objectfile = path.relative(path.absolute(pcoutputfile .. ".obj"), vcxprojdir) + local objectfile = path.relative(path.absolute(pcoutputfile .. ".obj"), target.project_dir) vcxprojfile:print("<ObjectFileName Condition=\"\'%$(Configuration)|%$(Platform)\'==\'%s|%s\'\">%s</ObjectFileName>", info.mode, info.arch, objectfile) end end @@ -785,7 +786,7 @@ function _make_source_file_forpch(vcxprojfile, vsinfo, target, vcxprojdir) end -- make source files -function _make_source_files(vcxprojfile, vsinfo, target, vcxprojdir) +function _make_source_files(vcxprojfile, vsinfo, target) -- add source files vcxprojfile:enter("<ItemGroup>") @@ -810,14 +811,14 @@ function _make_source_files(vcxprojfile, vsinfo, target, vcxprojdir) -- make source files for sourcefile, sourceinfo in pairs(sourceinfos) do if #sourceinfo == #target.info then - _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourceinfo, vcxprojdir) + _make_source_file_forall(vcxprojfile, vsinfo, target, sourcefile, sourceinfo) else - _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sourceinfo, vcxprojdir) + _make_source_file_forspec(vcxprojfile, vsinfo, target, sourcefile, sourceinfo) end end -- make precompiled source file - _make_source_file_forpch(vcxprojfile, vsinfo, target, vcxprojdir) + _make_source_file_forpch(vcxprojfile, vsinfo, target) vcxprojfile:leave("</ItemGroup>") @@ -827,7 +828,7 @@ function _make_source_files(vcxprojfile, vsinfo, target, vcxprojdir) for _, includefile in ipairs(target.headerfiles) do -- we need ignore pcheader file to fix https://github.com/xmake-io/xmake/issues/1171 if not pcheader or includefile ~= pcheader then - _make_header_file(vcxprojfile, includefile, vcxprojdir) + _make_header_file(vcxprojfile, includefile, target.project_dir) end end vcxprojfile:leave("</ItemGroup>") @@ -840,7 +841,7 @@ function make(vsinfo, target) local targetname = target.name -- the vcxproj directory - local vcxprojdir = path.join(vsinfo.solution_dir, targetname) + local vcxprojdir = target.project_dir -- open vcxproj file local vcxprojpath = path.join(vcxprojdir, targetname .. ".vcxproj") @@ -853,13 +854,13 @@ function make(vsinfo, target) _make_header(vcxprojfile, vsinfo) -- make Configurations - _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir) + _make_configurations(vcxprojfile, vsinfo, target) -- make common items - _make_common_items(vcxprojfile, vsinfo, target, vcxprojdir) + _make_common_items(vcxprojfile, vsinfo, target) -- make source files - _make_source_files(vcxprojfile, vsinfo, target, vcxprojdir) + _make_source_files(vcxprojfile, vsinfo, target) -- make tailer _make_tailer(vcxprojfile, vsinfo) |
