Skip to content

Commit

Permalink
Merge pull request #4707 from Arthapz/support-moduleonly-libraries
Browse files Browse the repository at this point in the history
Support moduleonly libraries
  • Loading branch information
waruqi authored Feb 11, 2024
2 parents c68dad9 + b6983ac commit a739684
Show file tree
Hide file tree
Showing 32 changed files with 406 additions and 146 deletions.
10 changes: 4 additions & 6 deletions tests/projects/c++/modules/link_order/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ add_rules("mode.release", "mode.debug")
set_languages("c++20")

target("foo")
add_rules("c++")
set_kind("static")
add_files("src/foo.mpp", {public = true})
set_kind("moduleonly")
add_files("src/foo.mpp")

target("bar")
add_rules("c++")
set_kind("static")
add_files("src/bar.mpp", {public = true})
set_kind("moduleonly")
add_files("src/bar.mpp")

target("link_order_1")
set_kind("binary")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ add_rules("mode.release", "mode.debug")
set_languages("c++20")

target("mod")
set_kind("static")
set_kind("moduleonly")
add_files("src/mod.mpp")
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export module bar2;

export namespace bar {
const char *hello2() {
return "Hello world";
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_rules("mode.release", "mode.debug")
set_languages("c++20")

target("bar2")
set_kind("moduleonly")
add_files("*.mpp")
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package("bar2")
set_kind("library")
set_sourcedir(path.join(os.scriptdir(), "src"))

on_install(function(package)
import("package.tools.xmake").install(package, {})
end)
2 changes: 2 additions & 0 deletions tests/projects/c++/modules/packages/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import foo;
import bar;
import bar2;

int main() {
foo::say(bar::hello());
foo::say(bar::hello2());
return 0;
}
4 changes: 2 additions & 2 deletions tests/projects/c++/modules/packages/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ add_rules("mode.release", "mode.debug")
set_languages("c++2b")

add_repositories("my-repo my-repo")
add_requires("foo", "bar")
add_requires("foo", "bar", "bar2")

target("packages")
set_kind("binary")
add_files("src/*.cpp")
add_packages("foo", "bar")
add_packages("foo", "bar", "bar2")
set_policy("build.c++.modules", true)
3 changes: 2 additions & 1 deletion tests/projects/c++/modules/staticlib/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ set_languages("c++20")

target("mod")
set_kind("static")
add_files("src/mod.mpp", "src/mod.cpp", {public = true})
add_files("src/mod.mpp", {public = true})
add_files("src/mod.cpp")

target("hello")
set_kind("binary")
Expand Down
5 changes: 3 additions & 2 deletions tests/projects/c++/modules/user_headerunit2/a/xmake.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
target("a")
set_kind("moduleonly")
add_headerfiles("*.hpp")
add_files("a.mpp")
set_languages("cxxlatest")
set_kind("object")
add_files("a.mpp", {public = true})
4 changes: 2 additions & 2 deletions tests/projects/c++/modules/user_headerunit2/b/xmake.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
target("b")
add_deps("a")
set_kind("moduleonly")
add_files("b.mpp")
set_languages("cxxlatest")
set_kind("object")
add_files("b.mpp", {public = true})
2 changes: 1 addition & 1 deletion xmake/actions/build/build.lua
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function _add_batchjobs_builtin(batchjobs, rootjob, target)
end

-- uses the builtin target script
if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object()) then
if not job and (target:is_static() or target:is_binary() or target:is_shared() or target:is_object() or target:is_moduleonly()) then
job, job_leaf = import("kinds." .. target:kind(), {anonymous = true})(batchjobs, rootjob, target)
end
job = job or rootjob
Expand Down
22 changes: 22 additions & 0 deletions xmake/actions/build/kinds/moduleonly.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--!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, TBOOX Open Source Group.
--
-- @author ruki, Arthapz
-- @file moduleonly.lua
--

-- imports
inherit("object")
100 changes: 100 additions & 0 deletions xmake/actions/package/local/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import("core.project.rule")
import("core.project.config")
import("core.project.project")
import("core.base.bit")
import("rules.c++.modules.modules_support.compiler_support", {alias = "module_compiler_support", rootdir = os.programdir()})
import("rules.c++.modules.modules_support.builder", {alias = "module_builder", rootdir = os.programdir()})

-- get library deps
function _get_librarydeps(target)
Expand Down Expand Up @@ -95,6 +97,7 @@ function _package_library(target)
local binarydir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "bin")
local librarydir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "lib")
local headerdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "include")
local modulesdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "modules")

-- copy the library file to the output directory
local targetfile = target:targetfile()
Expand Down Expand Up @@ -142,6 +145,30 @@ function _package_library(target)
end
end

-- copy modules
if target:data("cxx.has_modules") then

local modules = module_compiler_support.localcache():get2(target:name(), "c++.modules")
module_builder.generate_metadata(target, modules)

local sourcebatch = target:sourcebatches()["c++.build.modules.install"]
if sourcebatch and sourcebatch.sourcefiles then
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
local fileconfig = target:fileconfig(sourcefile)
local install = fileconfig and fileconfig.public or false
if install then
local modulehash = module_compiler_support.get_modulehash(target, sourcefile)
local prefixdir = path.join(modulesdir, modulehash)
os.vcp(sourcefile, path.join(prefixdir, path.filename(sourcefile)))
local metafile = module_compiler_support.get_metafile(target, sourcefile)
if os.exists(metafile) then
os.vcp(metafile, path.join(prefixdir, path.filename(metafile)))
end
end
end
end
end

-- generate xmake.lua
local file = io.open(path.join(packagedir, "xmake.lua"), "w")
if file then
Expand Down Expand Up @@ -261,6 +288,78 @@ function _package_headeronly(target)
print("package(%s): %s generated", packagename, packagedir)
end

function _package_moduleonly(target)

-- get the output directory
local packagedir = target:packagedir()
local packagename = target:name():lower()
local headerdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "include")
local modulesdir = path.join(packagedir, target:plat(), target:arch(), config.mode(), "modules")

local modules = module_compiler_support.localcache():get2(target:name(), "c++.modules")
module_builder.generate_metadata(target, modules)

-- copy headers
local srcheaders, dstheaders = target:headerfiles(headerdir)
if srcheaders and dstheaders then
local i = 1
for _, srcheader in ipairs(srcheaders) do
local dstheader = dstheaders[i]
if dstheader then
os.vcp(srcheader, dstheader)
end
i = i + 1
end
end

-- copy modules
local sourcebatch = target:sourcebatches()["c++.build.modules.install"]
if sourcebatch and sourcebatch.sourcefiles then
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
local modulehash = module_compiler_support.get_modulehash(target, sourcefile)
local prefixdir = path.join(modulesdir, modulehash)
os.vcp(sourcefile, path.join(prefixdir, path.filename(sourcefile)))
local metafile = module_compiler_support.get_metafile(target, sourcefile)
if os.exists(metafile) then
os.vcp(metafile, path.join(prefixdir, path.filename(metafile)))
end
end
end

-- generate xmake.lua
local file = io.open(path.join(packagedir, "xmake.lua"), "w")
if file then
local deps = _get_librarydeps(target)
file:print("package(\"%s\")", packagename)
local homepage = option.get("homepage")
if homepage then
file:print(" set_homepage(\"%s\")", homepage)
end
local description = option.get("description") or ("The " .. packagename .. " package")
file:print(" set_description(\"%s\")", description)
if target:license() then
file:print(" set_license(\"%s\")", target:license())
end
if #deps > 0 then
file:print(" add_deps(\"%s\")", table.concat(deps, "\", \""))
end
file:print("")
file:print([[
on_load(function (package)
package:set("installdir", path.join(os.scriptdir(), package:plat(), package:arch(), package:mode()))
end)
on_fetch(function (package)
local result = {}
result.includedirs = package:installdir("include")
return result
end)]])
file:close()
end

-- show tips
print("package(%s): %s generated", packagename, packagedir)
end
-- do package target
function _do_package_target(target)
if not target:is_phony() then
Expand All @@ -269,6 +368,7 @@ function _do_package_target(target)
binary = _package_binary
, static = _package_library
, shared = _package_library
, moduleonly = _package_moduleonly
, headeronly = _package_headeronly
}
local kind = target:kind()
Expand Down
9 changes: 7 additions & 2 deletions xmake/core/project/target.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1201,9 +1201,14 @@ function _instance:is_headeronly()
return self:kind() == "headeronly"
end

-- is moduleonly target?
function _instance:is_moduleonly()
return self:kind() == "moduleonly"
end

-- is library target?
function _instance:is_library()
return self:is_static() or self:is_shared() or self:is_headeronly()
return self:is_static() or self:is_shared() or self:is_headeronly() or self:is_moduleonly()
end

-- is default target?
Expand Down Expand Up @@ -1555,7 +1560,7 @@ end
function _instance:filename()

-- no target file?
if self:is_object() or self:is_phony() or self:is_headeronly() then
if self:is_object() or self:is_phony() or self:is_headeronly() or self:is_moduleonly() then
return
end

Expand Down
2 changes: 1 addition & 1 deletion xmake/modules/private/check/checkers/api/target/kind.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ import(".api_checker")

function main(opt)
opt = opt or {}
api_checker.check_targets("kind", table.join(opt, {values = {"object", "binary", "static", "shared", "headeronly", "phony"}}))
api_checker.check_targets("kind", table.join(opt, {values = {"object", "binary", "static", "shared", "headeronly", "moduleonly", "phony"}}))
end
9 changes: 9 additions & 0 deletions xmake/modules/target/action/uninstall/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ function _uninstall_files(target)
end
end

-- uninstall modules
function _uninstall_modules(target, opt)
local moduledir = path.join(target:installdir(), opt and opt.moduledir or "modules")
os.vrm(moduledir)
end

-- the builtin uninstall main entry
function main(target, opt)

Expand All @@ -47,6 +53,9 @@ function main(target, opt)
end
end

-- remove modules
_uninstall_modules(target, opt)

-- uninstall the other files
_uninstall_files(target)
end
Expand Down
13 changes: 11 additions & 2 deletions xmake/plugins/project/cmake/cmakelists.lua
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ end
function _escape_path(filepath)
if is_host("windows") then
filepath = filepath:gsub('\\', '/')
filepath = filepath:gsub(' ', '\\ ')
end
return filepath
end
Expand Down Expand Up @@ -323,6 +324,11 @@ function _add_target_headeronly(cmakelists, target)
cmakelists:print("add_library(%s INTERFACE)", target:name())
end

-- add target: headeronly
function _add_target_moduleonly(cmakelists, target)
cmakelists:print("add_custom_target(%s)", target:name())
end

-- add target dependencies
function _add_target_dependencies(cmakelists, target)
local deps = target:get("deps")
Expand All @@ -340,8 +346,8 @@ function _add_target_sources(cmakelists, target, outputdir)
local has_cuda = false
cmakelists:print("target_sources(%s PRIVATE", target:name())
local sourcebatches = target:sourcebatches()
for _, sourcebatch in table.orderpairs(sourcebatches) do
if _sourcebatch_is_built(sourcebatch) then
for name, sourcebatch in table.orderpairs(sourcebatches) do
if _sourcebatch_is_built(sourcebatch) and not name:startswith("c++.build.modules") then
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
cmakelists:print(" " .. _get_relative_unix_path(sourcefile, outputdir))
end
Expand Down Expand Up @@ -1003,6 +1009,9 @@ function _add_target(cmakelists, target, outputdir)
_add_target_headeronly(cmakelists, target)
_add_target_include_directories(cmakelists, target, outputdir)
return
elseif targetkind == 'moduleonly' then
_add_target_moduleonly(cmakelists, target)
return
else
raise("unknown target kind %s", target:kind())
end
Expand Down
Loading

0 comments on commit a739684

Please sign in to comment.