diff --git a/src/_manifest.lua b/src/_manifest.lua index f10130cb..986b6f95 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -76,6 +76,7 @@ "actions/vstudio/vs2005_csproj.lua", "actions/vstudio/vs2005_csproj_user.lua", "actions/vstudio/vs2010.lua", + "actions/vstudio/vs2010_nuget.lua", "actions/vstudio/vs2010_vcxproj.lua", "actions/vstudio/vs2010_vcxproj_user.lua", "actions/vstudio/vs2010_vcxproj_filters.lua", diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 92f109d1..9e90d532 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -748,6 +748,13 @@ } } + api.register { + name = "nuget", + scope = "project", + kind = "list:string", + tokens = true, + } + api.register { name = "objdir", scope = "config", diff --git a/src/actions/vstudio/_vstudio.lua b/src/actions/vstudio/_vstudio.lua index cd60b28a..9c246829 100644 --- a/src/actions/vstudio/_vstudio.lua +++ b/src/actions/vstudio/_vstudio.lua @@ -12,6 +12,23 @@ local config = p.config +-- +-- All valid .NET Framework versions, from oldest to newest. +-- + + vstudio.frameworkVersions = + { + "1.0", + "1.1", + "2.0", + "3.0", + "3.5", + "4.0", + "4.5", + "4.6", + } + + -- -- Mapping tables from Premake systems and architectures to Visual Studio -- identifiers. Broken out as tables so new values can be pushed in by diff --git a/src/actions/vstudio/vs2005.lua b/src/actions/vstudio/vs2005.lua index 54d66614..b75227fb 100644 --- a/src/actions/vstudio/vs2005.lua +++ b/src/actions/vstudio/vs2005.lua @@ -21,6 +21,20 @@ p.escaper(vs2005.esc) premake.generate(wks, ".sln", vstudio.sln2005.generate) + + if _ACTION >= "vs2010" then + -- Skip generation of empty NuGet packages.config files + if p.workspace.hasProject(wks, function(prj) return #prj.nuget > 0 end) then + premake.generate( + { + location = path.join(wks.location, "packages.config"), + workspace = wks + }, + nil, + vstudio.nuget2010.generatePackagesConfig + ) + end + end end diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index 09aaedb1..f9710540 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -29,7 +29,7 @@ "projectProperties", "configurations", "applicationIcon", - "assemblyReferences", + "references", } function cs2005.generate(prj) @@ -284,13 +284,29 @@ end +-- +-- Write out the references item group. +-- + + cs2005.elements.references = function(prj) + return { + cs2005.assemblyReferences, + cs2005.nuGetReferences, + } + end + + function cs2005.references(prj) + _p(1,'') + p.callArray(cs2005.elements.references, prj) + _p(1,'') + end + + -- -- Write the list of assembly (system, or non-sibling) references. -- function cs2005.assemblyReferences(prj) - _p(1,'') - -- C# doesn't support per-configuration links (does it?) so just use -- the settings from the first available config instead local cfg = project.getfirstconfig(prj) @@ -314,8 +330,44 @@ _x(2,'', name) end end) + end - _p(1,'') + +-- +-- Write the list of NuGet references. +-- + + function cs2005.nuGetReferences(prj) + if _ACTION >= "vs2010" then + for i = 1, #prj.nuget do + local package = prj.nuget[i] + _x(2, '', vstudio.nuget2010.packageId(package)) + + -- We need to write HintPaths for all supported framework + -- versions. The last HintPath will override any previous + -- HintPaths (if the condition is met that is). + + for _, frameworkVersion in ipairs(cs2005.identifyFrameworkVersions(prj)) do + local assembly = vstudio.path( + prj, + p.filename( + prj.solution, + string.format( + "packages\\%s\\lib\\%s\\%s.dll", + vstudio.nuget2010.packageName(package), + cs2005.formatNuGetFrameworkVersion(frameworkVersion), + vstudio.nuget2010.packageId(package) + ) + ) + ) + + _x(3, '%s', assembly, assembly) + end + + _p(3, 'True') + _p(2, '') + end + end end @@ -401,6 +453,41 @@ return string.format('Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"', premake.esc(vstudio.projectConfig(cfg))) end + +-- +-- Build and return a list of all .NET Framework versions up to and including +-- the project's framework version. +-- + + function cs2005.identifyFrameworkVersions(prj) + local frameworks = {} + + local cfg = p.project.getfirstconfig(prj) + local action = premake.action.current() + local targetFramework = cfg.dotnetframework or action.vstudio.targetFramework + + for _, frameworkVersion in ipairs(vstudio.frameworkVersions) do + if frameworkVersion == targetFramework then + break + end + + table.insert(frameworks, frameworkVersion) + end + + table.insert(frameworks, targetFramework) + + return frameworks + end + + +-- +-- When given a .NET Framework version, returns it formatted for NuGet. +-- + + function cs2005.formatNuGetFrameworkVersion(framework) + return "net" .. framework:gsub("%.", "") + end + --------------------------------------------------------------------------- -- -- Handlers for individual project elements diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua new file mode 100644 index 00000000..67a4b538 --- /dev/null +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -0,0 +1,83 @@ +-- +-- vs2010_nuget.lua +-- Generate a NuGet packages.config file. +-- Copyright (c) 2016 Jason Perkins and the Premake project +-- + + premake.vstudio.nuget2010 = {} + + local p = premake + local vstudio = p.vstudio + local nuget2010 = p.vstudio.nuget2010 + + +-- +-- These functions take the package string as an argument and give you +-- information about it. +-- + + function nuget2010.packageName(package) + return package:gsub(":", ".") + end + + function nuget2010.packageId(package) + return package:sub(0, package:find(":") - 1) + end + + function nuget2010.packageVersion(package) + return package:sub(package:find(":") + 1, -1) + end + + local function packageProject(wks, package) + for prj in p.workspace.eachproject(wks) do + for i = 1, #prj.nuget do + local projectPackage = prj.nuget[i] + + if projectPackage == package then + return prj + end + end + end + end + + function nuget2010.packageFramework(wks, package) + local prj = packageProject(wks, package) + + if p.project.iscpp(prj) then + return "native" + elseif p.project.isdotnet(prj) then + local cfg = p.project.getfirstconfig(prj) + local action = premake.action.current() + local framework = cfg.dotnetframework or action.vstudio.targetFramework + return cs2005.formatNuGetFrameworkVersion(framework) + end + end + + +-- +-- Generates the packages.config file. +-- + + function nuget2010.generatePackagesConfig(obj) + local wks = obj.workspace + + local packages = {} + for prj in p.workspace.eachproject(wks) do + for i = 1, #prj.nuget do + local package = prj.nuget[i] + + if not packages[package] then + packages[package] = true + end + end + end + + p.w('') + p.push('') + + for package in pairs(packages) do + p.x('', nuget2010.packageId(package), nuget2010.packageVersion(package), nuget2010.packageFramework(wks, package)) + end + + p.pop('') + end diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 52466300..c4d42a50 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -46,6 +46,7 @@ m.projectReferences, m.importLanguageTargets, m.importExtensionTargets, + m.ensureNuGetPackageBuildImports, } end @@ -1385,6 +1386,7 @@ return { m.importGroupTargets, m.importRuleTargets, + m.importNuGetTargets, m.importBuildCustomizationsTargets } end @@ -1412,6 +1414,17 @@ end end + local function nuGetTargetsFile(prj, package) + return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s\\build\\native\\%s.targets", vstudio.nuget2010.packageName(package), vstudio.nuget2010.packageId(package)))) + end + + function m.importNuGetTargets(prj) + for i = 1, #prj.nuget do + local targetsFile = nuGetTargetsFile(prj, prj.nuget[i]) + p.x('', targetsFile, targetsFile) + end + end + function m.importBuildCustomizationsTargets(prj) for i, build in ipairs(prj.buildcustomizations) do p.w('', path.translate(build)) @@ -1420,6 +1433,21 @@ + function m.ensureNuGetPackageBuildImports(prj) + p.push('') + p.push('') + p.x('This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.') + p.pop('') + + for i = 1, #prj.nuget do + local targetsFile = nuGetTargetsFile(prj, prj.nuget[i]) + p.x('', targetsFile, targetsFile) + end + p.pop('') + end + + + function m.importDefaultProps(prj) p.w('') end diff --git a/tests/_tests.lua b/tests/_tests.lua index a6781b84..4d778e26 100644 --- a/tests/_tests.lua +++ b/tests/_tests.lua @@ -82,6 +82,7 @@ return { "actions/vstudio/sln2005/test_projects.lua", "actions/vstudio/sln2005/test_platforms.lua", "actions/vstudio/sln2005/test_sections.lua", + "actions/vstudio/sln2005/test_nuget_packages_config.lua", -- Visual Studio 2002-2008 C/C++ projects "actions/vstudio/vc200x/test_assembly_refs.lua", @@ -134,6 +135,7 @@ return { "actions/vstudio/vc2010/test_target_machine.lua", "actions/vstudio/vc2010/test_user_file.lua", "actions/vstudio/vc2010/test_vectorextensions.lua", + "actions/vstudio/vc2010/test_ensure_nuget_imports.lua", -- Makefile tests "actions/make/test_make_escaping.lua", diff --git a/tests/actions/vstudio/cs2005/test_assembly_refs.lua b/tests/actions/vstudio/cs2005/test_assembly_refs.lua index 87bf2d0f..e8ebdbce 100644 --- a/tests/actions/vstudio/cs2005/test_assembly_refs.lua +++ b/tests/actions/vstudio/cs2005/test_assembly_refs.lua @@ -16,14 +16,14 @@ local wks, prj function suite.setup() - premake.action.set("vs2008") + premake.action.set("vs2010") wks = test.createWorkspace() language "C#" end local function prepare(platform) prj = test.getproject(wks, 1) - cs2005.assemblyReferences(prj) + cs2005.references(prj) end @@ -142,3 +142,50 @@ ]] end + +-- +-- NuGet packages should get references. +-- + + function suite.nuGetPackages() + dotnetframework "4.5" + nuget { "Newtonsoft.Json:7.0.1" } + prepare() + test.capture [[ + + + packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net35\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + True + + + ]] + end + + +-- +-- NuGet packages shouldn't get HintPaths for .NET Framework +-- versions that the project doesn't support. +-- + + function suite.nuGetPackages_olderNET() + dotnetframework "3.0" + nuget { "Newtonsoft.Json:7.0.1" } + prepare() + test.capture [[ + + + packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll + packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll + True + + + ]] + end diff --git a/tests/actions/vstudio/sln2005/test_nuget_packages_config.lua b/tests/actions/vstudio/sln2005/test_nuget_packages_config.lua new file mode 100644 index 00000000..f383efa9 --- /dev/null +++ b/tests/actions/vstudio/sln2005/test_nuget_packages_config.lua @@ -0,0 +1,43 @@ +-- +-- tests/actions/vstudio/sln2005/test_nuget_packages_config.lua +-- Validate generation of NuGet packages.config file for Visual Studio 2010 and newer. +-- Copyright (c) 2016 Jason Perkins and the Premake project +-- + + local suite = test.declare("vstudio_sln2005_nuget_packages_config") + local nuget2010 = premake.vstudio.nuget2010 + + +-- +-- Setup +-- + + local wks + + function suite.setup() + premake.action.set("vs2010") + wks = test.createWorkspace() + end + + local function prepare() + local prj = premake.solution.getproject(wks, 1) + nuget2010.generatePackagesConfig({ workspace = wks }) + end + + +-- +-- Writes the packages.config file properly. +-- + + function suite.structureIsCorrect() + nuget { "boost:1.59.0-b1", "sdl2.v140:2.0.3", "sdl2.v140.redist:2.0.3" } + prepare() + test.capture [[ + + + + + + + ]] + end diff --git a/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua b/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua new file mode 100644 index 00000000..2c747fec --- /dev/null +++ b/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua @@ -0,0 +1,46 @@ +-- +-- tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua +-- Check the EnsureNuGetPackageBuildImports block of a VS 2010 project. +-- Copyright (c) 2016 Jason Perkins and the Premake project +-- + + local suite = test.declare("vs2010_ensure_nuget_imports") + local vc2010 = premake.vstudio.vc2010 + local project = premake.project + + +-- +-- Setup +-- + + local wks + + function suite.setup() + premake.action.set("vs2010") + wks = test.createWorkspace() + end + + local function prepare() + local prj = premake.solution.getproject(wks, 1) + vc2010.ensureNuGetPackageBuildImports(prj) + end + + +-- +-- Writes the pre-build check that makes sure that all packages are installed. +-- + + function suite.structureIsCorrect() + nuget { "boost:1.59.0-b1", "sdl2.v140:2.0.3", "sdl2.v140.redist:2.0.3" } + prepare() + test.capture [[ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + ]] + end diff --git a/tests/actions/vstudio/vc2010/test_extension_targets.lua b/tests/actions/vstudio/vc2010/test_extension_targets.lua index 40d1720a..5575a2b5 100644 --- a/tests/actions/vstudio/vc2010/test_extension_targets.lua +++ b/tests/actions/vstudio/vc2010/test_extension_targets.lua @@ -58,6 +58,23 @@ end +-- +-- Writes entries for NuGet packages. +-- + + function suite.addsImport_onEachNuGetPackage() + nuget { "boost:1.59.0-b1", "sdl2.v140:2.0.3", "sdl2.v140.redist:2.0.3" } + prepare() + test.capture [[ + + + + + + ]] + end + + -- -- Rule files use a project relative path. --