diff --git a/xmake/plugins/project/cmake/cmakelists.lua b/xmake/plugins/project/cmake/cmakelists.lua index fed2f7e42ce..eea74d04fb0 100644 --- a/xmake/plugins/project/cmake/cmakelists.lua +++ b/xmake/plugins/project/cmake/cmakelists.lua @@ -43,18 +43,19 @@ function _get_cmake_minver() end -- get unix path -function _get_unix_path(filepath) +function _get_unix_path(filepath, outputdir) if path.is_absolute(filepath) and filepath:startswith(os.projectdir()) then filepath = path.relative(filepath, os.projectdir()) end + filepath = path.relative(filepath, outputdir) filepath = path.translate(filepath):gsub('\\', '/') return os.args(filepath) end -- get unix path relative to the cmake path -- @see https://github.com/xmake-io/xmake/issues/2026 -function _get_unix_path_relative_to_cmake(filepath) - filepath = _get_unix_path(filepath) +function _get_unix_path_relative_to_cmake(filepath, outputdir) + filepath = _get_unix_path(filepath, outputdir) if filepath and not path.is_absolute(filepath) then filepath = "${CMAKE_SOURCE_DIR}/" .. filepath end @@ -94,7 +95,7 @@ function _get_configs_from_target(target, name) end -- add project info -function _add_project(cmakelists, languages) +function _add_project(cmakelists, languages, outputdir) local cmake_version = _get_cmake_minver() cmakelists:print([[# this is the build file for project %s @@ -148,29 +149,29 @@ function _add_target_phony(cmakelists, target) end -- add target: binary -function _add_target_binary(cmakelists, target) +function _add_target_binary(cmakelists, target, outputdir) cmakelists:print("add_executable(%s \"\")", target:name()) cmakelists:print("set_target_properties(%s PROPERTIES OUTPUT_NAME \"%s\")", target:name(), target:basename()) - cmakelists:print("set_target_properties(%s PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir())) + cmakelists:print("set_target_properties(%s PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir(), outputdir)) end -- add target: static -function _add_target_static(cmakelists, target) +function _add_target_static(cmakelists, target, outputdir) cmakelists:print("add_library(%s STATIC \"\")", target:name()) cmakelists:print("set_target_properties(%s PROPERTIES OUTPUT_NAME \"%s\")", target:name(), target:basename()) - cmakelists:print("set_target_properties(%s PROPERTIES ARCHIVE_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir())) + cmakelists:print("set_target_properties(%s PROPERTIES ARCHIVE_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir(), outputdir)) end -- add target: shared -function _add_target_shared(cmakelists, target) +function _add_target_shared(cmakelists, target, outputdir) cmakelists:print("add_library(%s SHARED \"\")", target:name()) cmakelists:print("set_target_properties(%s PROPERTIES OUTPUT_NAME \"%s\")", target:name(), target:basename()) if target:is_plat("windows") then -- @see https://github.com/xmake-io/xmake/issues/2192 - cmakelists:print("set_target_properties(%s PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir())) - cmakelists:print("set_target_properties(%s PROPERTIES ARCHIVE_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir())) + cmakelists:print("set_target_properties(%s PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir(), outputdir)) + cmakelists:print("set_target_properties(%s PROPERTIES ARCHIVE_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir(), outputdir)) else - cmakelists:print("set_target_properties(%s PROPERTIES LIBRARY_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir())) + cmakelists:print("set_target_properties(%s PROPERTIES LIBRARY_OUTPUT_DIRECTORY \"%s\")", target:name(), _get_unix_path_relative_to_cmake(target:targetdir(), outputdir)) end end @@ -192,14 +193,14 @@ function _add_target_dependencies(cmakelists, target) end -- add target sources -function _add_target_sources(cmakelists, target) +function _add_target_sources(cmakelists, target, outputdir) local has_cuda = false cmakelists:print("target_sources(%s PRIVATE", target:name()) for _, sourcebatch in table.orderpairs(target:sourcebatches()) do local sourcekind = sourcebatch.sourcekind if sourcekind == "cc" or sourcekind == "cxx" or sourcekind == "as" or sourcekind == "cu" then for _, sourcefile in ipairs(sourcebatch.sourcefiles) do - cmakelists:print(" " .. _get_unix_path(sourcefile)) + cmakelists:print(" " .. _get_unix_path(sourcefile, outputdir)) end end if sourcekind == "cu" then @@ -207,7 +208,7 @@ function _add_target_sources(cmakelists, target) end end for _, headerfile in ipairs(target:headerfiles()) do - cmakelists:print(" " .. _get_unix_path(headerfile)) + cmakelists:print(" " .. _get_unix_path(headerfile, outputdir)) end cmakelists:print(")") if has_cuda then @@ -221,7 +222,7 @@ end -- add target source groups -- @see https://github.com/xmake-io/xmake/issues/1149 -function _add_target_source_groups(cmakelists, target) +function _add_target_source_groups(cmakelists, target, outputdir) local filegroups = target:get("filegroups") for _, filegroup in ipairs(filegroups) do local files = target:extraconf("filegroups", filegroup, "files") or "**" @@ -231,60 +232,60 @@ function _add_target_source_groups(cmakelists, target) local sources = {} local recurse_sources = {} if path.is_absolute(rootdir) then - rootdir = _get_unix_path(rootdir) + rootdir = _get_unix_path(rootdir, outputdir) else - rootdir = string.format("${CMAKE_CURRENT_SOURCE_DIR}/%s", _get_unix_path(rootdir)) + rootdir = string.format("${CMAKE_CURRENT_SOURCE_DIR}/%s", _get_unix_path(rootdir, outputdir)) end for _, filepattern in ipairs(files) do if filepattern:find("**", 1, true) then filepattern = filepattern:gsub("%*%*", "*") - table.insert(recurse_sources, _get_unix_path(path.join(rootdir, filepattern))) + table.insert(recurse_sources, _get_unix_path(path.join(rootdir, filepattern), outputdir)) else - table.insert(sources, _get_unix_path(path.join(rootdir, filepattern))) + table.insert(sources, _get_unix_path(path.join(rootdir, filepattern), outputdir)) end end if #sources > 0 then cmakelists:print("FILE(GLOB %s_GROUP_SOURCE_LIST %s)", target:name(), table.concat(sources, " ")) if mode and mode == "plain" then cmakelists:print("source_group(%s FILES ${%s_GROUP_SOURCE_LIST})", - _get_unix_path(filegroup), target:name()) + _get_unix_path(filegroup, outputdir), target:name()) else cmakelists:print("source_group(TREE %s PREFIX %s FILES ${%s_GROUP_SOURCE_LIST})", - rootdir, _get_unix_path(filegroup), target:name()) + rootdir, _get_unix_path(filegroup, outputdir), target:name()) end end if #recurse_sources > 0 then cmakelists:print("FILE(GLOB_RECURSE %s_GROUP_RECURSE_SOURCE_LIST %s)", target:name(), table.concat(recurse_sources, " ")) if mode and mode == "plain" then cmakelists:print("source_group(%s FILES ${%s_GROUP_RECURSE_SOURCE_LIST})", - _get_unix_path(filegroup), target:name()) + _get_unix_path(filegroup, outputdir), target:name()) else cmakelists:print("source_group(TREE %s PREFIX %s FILES ${%s_GROUP_RECURSE_SOURCE_LIST})", - rootdir, _get_unix_path(filegroup), target:name()) + rootdir, _get_unix_path(filegroup, outputdir), target:name()) end end end end --- add target precompilied header -function _add_target_precompiled_header(cmakelists, target) +-- add target precompiled header +function _add_target_precompiled_header(cmakelists, target, outputdir) local precompiled_header = target:get("pcheader") or target:get("pcxxheader") if precompiled_header then cmakelists:print("target_precompile_headers(%s PRIVATE", target:name()) cmakelists:print(" $<$:${CMAKE_CURRENT_SOURCE_DIR}/%s>", target:get("pcxxheader") and "CXX" or "C", - _get_unix_path(precompiled_header)) + _get_unix_path(precompiled_header, outputdir)) cmakelists:print(")") end end -- add target include directories -function _add_target_include_directories(cmakelists, target) +function _add_target_include_directories(cmakelists, target, outputdir) local includedirs = _get_configs_from_target(target, "includedirs") if #includedirs > 0 then cmakelists:print("target_include_directories(%s PRIVATE", target:name()) for _, includedir in ipairs(includedirs) do - cmakelists:print(" " .. _get_unix_path(includedir)) + cmakelists:print(" " .. _get_unix_path(includedir, outputdir)) end cmakelists:print(")") end @@ -294,27 +295,27 @@ function _add_target_include_directories(cmakelists, target) if includedirs_interface then cmakelists:print("target_include_directories(%s INTERFACE", target:name()) for _, headerdir in ipairs(includedirs_interface) do - cmakelists:print(" " .. _get_unix_path(headerdir)) + cmakelists:print(" " .. _get_unix_path(headerdir, outputdir)) end cmakelists:print(")") end -- export config header directory (deprecated) local configheader = target:configheader() if configheader then - cmakelists:print("target_include_directories(%s PUBLIC %s)", target:name(), _get_unix_path(path.directory(configheader))) + cmakelists:print("target_include_directories(%s PUBLIC %s)", target:name(), _get_unix_path(path.directory(configheader), outputdir)) end end -- add target system include directories -- we disable system/external includes first, because cmake doesn’t seem to be able to support msvc /external:I -- https://github.com/xmake-io/xmake/issues/1050 -function _add_target_sysinclude_directories(cmakelists, target) +function _add_target_sysinclude_directories(cmakelists, target, outputdir) local includedirs = _get_configs_from_target(target, "sysincludedirs") if #includedirs > 0 then -- TODO should be `SYSTEM PRIVATE` cmakelists:print("target_include_directories(%s PRIVATE", target:name()) for _, includedir in ipairs(includedirs) do - cmakelists:print(" " .. _get_unix_path(includedir)) + cmakelists:print(" " .. _get_unix_path(includedir, outputdir)) end cmakelists:print(")") end @@ -322,7 +323,7 @@ function _add_target_sysinclude_directories(cmakelists, target) if includedirs_interface then cmakelists:print("target_include_directories(%s INTERFACE", target:name()) for _, headerdir in ipairs(includedirs_interface) do - cmakelists:print(" " .. _get_unix_path(headerdir)) + cmakelists:print(" " .. _get_unix_path(headerdir, outputdir)) end cmakelists:print(")") end @@ -543,27 +544,27 @@ function _add_target_link_libraries(cmakelists, target) end -- add target link directories -function _add_target_link_directories(cmakelists, target) +function _add_target_link_directories(cmakelists, target, outputdir) local linkdirs = _get_configs_from_target(target, "linkdirs") if #linkdirs > 0 then local cmake_minver = _get_cmake_minver() if cmake_minver:ge("3.13.0") then cmakelists:print("target_link_directories(%s PRIVATE", target:name()) for _, linkdir in ipairs(linkdirs) do - cmakelists:print(" " .. _get_unix_path(linkdir)) + cmakelists:print(" " .. _get_unix_path(linkdir, outputdir)) end cmakelists:print(")") else cmakelists:print("if(MSVC)") cmakelists:print(" target_link_libraries(%s PRIVATE", target:name()) for _, linkdir in ipairs(linkdirs) do - cmakelists:print(" -libpath:" .. _get_unix_path(linkdir)) + cmakelists:print(" -libpath:" .. _get_unix_path(linkdir, outputdir)) end cmakelists:print(" )") cmakelists:print("else()") cmakelists:print(" target_link_libraries(%s PRIVATE", target:name()) for _, linkdir in ipairs(linkdirs) do - cmakelists:print(" -L" .. _get_unix_path(linkdir)) + cmakelists:print(" -L" .. _get_unix_path(linkdir, outputdir)) end cmakelists:print(" )") cmakelists:print("endif()") @@ -598,7 +599,7 @@ function _add_target_link_options(cmakelists, target) end -- get command string -function _get_command_string(cmd) +function _get_command_string(cmd, outputdir) local kind = cmd.kind local opt = cmd.opt if cmd.program then @@ -606,32 +607,32 @@ function _get_command_string(cmd) local argv = {} for _, v in ipairs(table.join(cmd.program, cmd.argv)) do if path.is_absolute(v) then - v = _get_unix_path_relative_to_cmake(v) + v = _get_unix_path_relative_to_cmake(v, outputdir) end table.insert(argv, v) end local command = os.args(argv) if opt and opt.curdir then - command = "${CMAKE_COMMAND} -E chdir " .. _get_unix_path_relative_to_cmake(opt.curdir) .. " " .. command + command = "${CMAKE_COMMAND} -E chdir " .. _get_unix_path_relative_to_cmake(opt.curdir, outputdir) .. " " .. command end return command elseif kind == "cp" then if os.isdir(cmd.srcpath) then return string.format("${CMAKE_COMMAND} -E copy_directory %s %s", - _get_unix_path_relative_to_cmake(cmd.srcpath), _get_unix_path_relative_to_cmake(cmd.dstpath)) + _get_unix_path_relative_to_cmake(cmd.srcpath, outputdir), _get_unix_path_relative_to_cmake(cmd.dstpath, outputdir)) else return string.format("${CMAKE_COMMAND} -E copy %s %s", - _get_unix_path_relative_to_cmake(cmd.srcpath), _get_unix_path_relative_to_cmake(cmd.dstpath)) + _get_unix_path_relative_to_cmake(cmd.srcpath, outputdir), _get_unix_path_relative_to_cmake(cmd.dstpath, outputdir)) end elseif kind == "rm" then - return string.format("${CMAKE_COMMAND} -E rm -rf %s", _get_unix_path_relative_to_cmake(cmd.filepath)) + return string.format("${CMAKE_COMMAND} -E rm -rf %s", _get_unix_path_relative_to_cmake(cmd.filepath, outputdir)) elseif kind == "mv" then return string.format("${CMAKE_COMMAND} -E rename %s %s", - _get_unix_path_relative_to_cmake(cmd.srcpath), _get_unix_path_relative_to_cmake(cmd.dstpath)) + _get_unix_path_relative_to_cmake(cmd.srcpath, outputdir), _get_unix_path_relative_to_cmake(cmd.dstpath, outputdir)) elseif kind == "cd" then - return string.format("cd %s", _get_unix_path_relative_to_cmake(cmd.dir)) + return string.format("cd %s", _get_unix_path_relative_to_cmake(cmd.dir, outputdir)) elseif kind == "mkdir" then - return string.format("${CMAKE_COMMAND} -E make_directory %s", _get_unix_path_relative_to_cmake(cmd.dir)) + return string.format("${CMAKE_COMMAND} -E make_directory %s", _get_unix_path_relative_to_cmake(cmd.dir, outputdir)) elseif kind == "show" then return string.format("echo %s", cmd.showtext) end @@ -666,7 +667,7 @@ function _add_target_custom_command(cmakelists, target, command, suffix) end -- add target custom commands for target -function _add_target_custom_commands_for_target(cmakelists, target, suffix) +function _add_target_custom_commands_for_target(cmakelists, target, outputdir, suffix) for _, ruleinst in ipairs(target:orderules()) do local scriptname = "buildcmd" .. (suffix and ("_" .. suffix) or "") local script = ruleinst:script(scriptname) @@ -675,7 +676,7 @@ function _add_target_custom_commands_for_target(cmakelists, target, suffix) script(target, batchcmds_, {}) if not batchcmds_:empty() then for _, cmd in ipairs(batchcmds_:cmds()) do - local command = _get_command_string(cmd) + local command = _get_command_string(cmd, outputdir) if command then _add_target_custom_command(cmakelists, target, command, suffix) end @@ -686,7 +687,7 @@ function _add_target_custom_commands_for_target(cmakelists, target, suffix) end -- add target custom commands for object rules -function _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, suffix) +function _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir, suffix) -- get rule local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!") @@ -700,7 +701,7 @@ function _add_target_custom_commands_for_objectrules(cmakelists, target, sourceb script(target, batchcmds_, sourcebatch, {}) if not batchcmds_:empty() then for _, cmd in ipairs(batchcmds_:cmds()) do - local command = _get_command_string(cmd) + local command = _get_command_string(cmd, outputdir) if command then _add_target_custom_command(cmakelists, target, command, suffix) end @@ -719,7 +720,7 @@ function _add_target_custom_commands_for_objectrules(cmakelists, target, sourceb script(target, batchcmds_, sourcefile, {}) if not batchcmds_:empty() then for _, cmd in ipairs(batchcmds_:cmds()) do - local command = _get_command_string(cmd) + local command = _get_command_string(cmd, outputdir) if command then _add_target_custom_command(cmakelists, target, command, suffix) end @@ -731,17 +732,17 @@ function _add_target_custom_commands_for_objectrules(cmakelists, target, sourceb end -- add target custom commands -function _add_target_custom_commands(cmakelists, target) - _add_target_custom_commands_for_target(cmakelists, target, "before") +function _add_target_custom_commands(cmakelists, target, outputdir) + _add_target_custom_commands_for_target(cmakelists, target, outputdir, "before") for _, sourcebatch in table.orderpairs(target:sourcebatches()) do local sourcekind = sourcebatch.sourcekind if sourcekind ~= "cc" and sourcekind ~= "cxx" and sourcekind ~= "as" then - _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, "before") - _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch) - _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, "after") + _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir, "before") + _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir) + _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir, "after") end end - _add_target_custom_commands_for_target(cmakelists, target, "after") + _add_target_custom_commands_for_target(cmakelists, target, outputdir, "after") end -- TODO export target headers (deprecated) @@ -760,7 +761,7 @@ function _export_target_headers(target) end -- add target -function _add_target(cmakelists, target) +function _add_target(cmakelists, target, outputdir) -- add comment cmakelists:print("# target") @@ -770,14 +771,14 @@ function _add_target(cmakelists, target) if target:is_phony() then return _add_target_phony(cmakelists, target) elseif targetkind == "binary" then - _add_target_binary(cmakelists, target) + _add_target_binary(cmakelists, target, outputdir) elseif targetkind == "static" then - _add_target_static(cmakelists, target) + _add_target_static(cmakelists, target, outputdir) elseif targetkind == "shared" then - _add_target_shared(cmakelists, target) + _add_target_shared(cmakelists, target, outputdir) elseif targetkind == 'headeronly' then _add_target_headeronly(cmakelists, target) - _add_target_include_directories(cmakelists, target) + _add_target_include_directories(cmakelists, target, outputdir) return else raise("unknown target kind %s", target:kind()) @@ -790,13 +791,13 @@ function _add_target(cmakelists, target) _add_target_dependencies(cmakelists, target) -- add target precompilied header - _add_target_precompiled_header(cmakelists, target) + _add_target_precompiled_header(cmakelists, target, outputdir) -- add target include directories - _add_target_include_directories(cmakelists, target) + _add_target_include_directories(cmakelists, target, outputdir) -- add target system include directories - _add_target_sysinclude_directories(cmakelists, target) + _add_target_sysinclude_directories(cmakelists, target, outputdir) -- add target compile definitions _add_target_compile_definitions(cmakelists, target) @@ -823,33 +824,33 @@ function _add_target(cmakelists, target) _add_target_link_libraries(cmakelists, target) -- add target link directories - _add_target_link_directories(cmakelists, target) + _add_target_link_directories(cmakelists, target, outputdir) -- add target link options _add_target_link_options(cmakelists, target) -- add target custom commands - _add_target_custom_commands(cmakelists, target) + _add_target_custom_commands(cmakelists, target, outputdir) -- add target sources - _add_target_sources(cmakelists, target) + _add_target_sources(cmakelists, target, outputdir) -- add target source groups - _add_target_source_groups(cmakelists, target) + _add_target_source_groups(cmakelists, target, outputdir) -- end cmakelists:print("") end -- generate cmakelists -function _generate_cmakelists(cmakelists) +function _generate_cmakelists(cmakelists, outputdir) -- add project info - _add_project(cmakelists, _get_project_languages(project.targets())) + _add_project(cmakelists, _get_project_languages(project.targets()), outputdir) -- add targets for _, target in table.orderpairs(project.targets()) do - _add_target(cmakelists, target) + _add_target(cmakelists, target, outputdir) end end @@ -863,7 +864,7 @@ function make(outputdir) local cmakelists = io.open(path.join(outputdir, "CMakeLists.txt"), "w") -- generate cmakelists - _generate_cmakelists(cmakelists) + _generate_cmakelists(cmakelists, outputdir) -- close the cmakelists cmakelists:close()