feature-request:解决或提示静态库生成名称冲突
你在什么场景下需要该功能?
参考以下的项目示例:(基于xmake 3.0.4,linux x86_64)
xmake.lua
target("a::util")
set_kind("static")
add_files("a-util.cpp")
add_headerfiles("a-util.hpp")
target("b::util")
set_kind("static")
add_files("b-util.cpp")
add_headerfiles("b-util.hpp")
target("main")
set_kind("binary")
add_files("main.cpp")
add_deps("a::util", "b::util")
main.cpp
#include <iostream>
#include "a-util.hpp"
#include "b-util.hpp"
int main()
{
std::cout << a::util::func() << b::util::func() << '\n';
return 0;
}
a-util.hpp
namespace a::util
{
int func();
}
b-util.hpp相似,不再重复
a-util.cpp
#include "a-util.hpp"
int a::util::func()
{
return 1;
}
b-util.cpp相似,不再重复
冲突情形
项目在编译时,静态库a::util和b::util的默认生成名称(basename)均为util,生成的库名称均为libutil.a。链接时,xmake在参数中生成了-lutil,但链接器的搜索路径下同时存在两个libutil.a,因此只链接了其中一个库。尽管这种情况可以通过设置set_basename("a-util")来解决,但是出现类似这种错误时,通常只会产生链接错误,用户没法第一时间想到生成名称的问题。
如果设置了set_policy("build.intermediate_directory", false),两个冲突的库会彼此覆盖,导致了相同问题。
链接参数:
/usr/local/bin/g++ -o build/linux/x86_64/release/main build/.objs/main/linux/x86_64/release/main.cpp.o -m64 -Lbuild/linux/x86_64/release/a -Lbuild/linux/x86_64/release/b -lutil出现错误的提示:
❯ xmake build main [ 87%]: linking.release main error: /usr/bin/ld: build/.objs/main/linux/x86_64/release/main.cpp.o: in function `main': main.cpp:(.text+0x1e): undefined reference to `b::util::func()' collect2: error: ld returned 1 exit status
描述可能的解决方案
潜在解决方案:
- 添加检查,出现冲突时自动停止编译
- 更改默认命名规则,将命名空间纳入
且这两种方案可以并行存在,见“候选方案”一节
描述你认为的候选方案
方案1
xmake自动检查目标文件名冲突情况,如果存在冲突则停止编译并发出告警。
示例:
> xmake build
error: conflicting basename for target a::util and b::util! Use set_basename to resolve the conflict, see documentation for usage
方案2
更改默认命名规则(例如,a::util的basename从util变更为a-util,b::util变更为b-util,分别生成liba-util.a和libb-util.a)。这种方案可避免绝大部分情况下的冲突。
这种方案也可以和方案1并行,例如当存在a::util和a-util时,两者的目标文件名同样发生了冲突,方案1同样可以发出告警,通知用户通过set_basename更改名称
其他信息
前文提到的项目示例:example.tar.gz
https://xmake.io/zh/guide/project-configuration/namespace-isolation.html#namespace-isolation https://xmake.io/zh/api/description/global-interfaces.html#namespace
https://xmake.io/zh/guide/project-configuration/namespace-isolation.html#namespace-isolation https://xmake.io/zh/api/description/global-interfaces.html#namespace
用文档里面的方法显式地指定如下:
xmake.lua
namespace("a")
includes("a-util.lua")
namespace_end()
namespace("b")
includes("b-util.lua")
namespace_end()
target("main")
set_kind("binary")
add_files("main.cpp")
add_deps("a::util", "b::util")
a-util.lua
target("util")
set_kind("static")
add_files("a-util.cpp")
add_headerfiles("a-util.hpp")
b-util.lua
target("util")
set_kind("static")
add_files("b-util.cpp")
add_headerfiles("b-util.hpp")
产生了完全一致的行为,目标文件名均发生冲突。
Issue中的:
❯ xmake build -rv main
checking for gcc ... /usr/local/bin/gcc
checking for nim ... no
checking for g++ ... /usr/local/bin/g++
checking for the c++ compiler (cxx) ... g++
checking for /usr/local/bin/g++ ... ok
checking for flags (-fPIC) ... ok
[ 47%]: cache compiling.release main.cpp
/usr/local/bin/g++ -c -m64 -o build/.objs/main/linux/x86_64/release/main.cpp.o main.cpp
checking for flags (-MMD -MF) ... ok
checking for flags (-fdiagnostics-color=always) ... ok
checking for flags (-Wno-gnu-line-marker -Werror) ... ok
checking for the c++ compiler (cxx) ... g++
[ 47%]: cache compiling.release a::a-util.cpp
/usr/local/bin/g++ -c -m64 -o build/.objs/a/util/linux/x86_64/release/a-util.cpp.o a-util.cpp
checking for the c++ compiler (cxx) ... g++
[ 47%]: cache compiling.release b::b-util.cpp
/usr/local/bin/g++ -c -m64 -o build/.objs/b/util/linux/x86_64/release/b-util.cpp.o b-util.cpp
checking for ar ... /usr/bin/ar
checking for the static library archiver (ar) ... ar
[ 63%]: linking.release a::libutil.a
/usr/bin/ar -cr build/linux/x86_64/release/a/libutil.a build/.objs/a/util/linux/x86_64/release/a-util.cpp.o
checking for the static library archiver (ar) ... ar
[ 71%]: linking.release b::libutil.a
/usr/bin/ar -cr build/linux/x86_64/release/b/libutil.a build/.objs/b/util/linux/x86_64/release/b-util.cpp.o
checking for g++ ... /usr/local/bin/g++
checking for the linker (ld) ... g++
checking for flags (-fPIC) ... ok
[ 87%]: linking.release main
/usr/local/bin/g++ -o build/linux/x86_64/release/main build/.objs/main/linux/x86_64/release/main.cpp.o -m64 -Lbuild/linux/x86_64/release/a -Lbuild/linux/x86_64/release/b -lutil
/usr/bin/ld: build/.objs/main/linux/x86_64/release/main.cpp.o: in function `main':
main.cpp:(.text+0x1e): undefined reference to `b::util::func()'
collect2: error: ld returned 1 exit status
error: execv(/usr/local/bin/g++ -o build/linux/x86_64/release/main build/.objs/main/linux/x86_64/release/main.cpp.o -m64 -Lbuild/linux/x86_64/release/a -Lbuild/linux/x86_64/release/b -lutil) failed(1)
显式指定:
❯ xmake build -rv main
[ 31%]: cache compiling.release main.cpp
/usr/local/bin/g++ -c -m64 -o build/.objs/main/linux/x86_64/release/main.cpp.o main.cpp
[ 39%]: cache compiling.release a::a-util.cpp
/usr/local/bin/g++ -c -m64 -o build/.objs/a/util/linux/x86_64/release/a-util.cpp.o a-util.cpp
[ 47%]: cache compiling.release b::b-util.cpp
/usr/local/bin/g++ -c -m64 -o build/.objs/b/util/linux/x86_64/release/b-util.cpp.o b-util.cpp
checking for flags (-MMD -MF) ... ok
checking for flags (-fdiagnostics-color=always) ... ok
checking for flags (-Wno-gnu-line-marker -Werror) ... ok
[ 55%]: linking.release b::libutil.a
/usr/bin/ar -cr build/linux/x86_64/release/b/libutil.a build/.objs/b/util/linux/x86_64/release/b-util.cpp.o
[ 63%]: linking.release a::libutil.a
/usr/bin/ar -cr build/linux/x86_64/release/a/libutil.a build/.objs/a/util/linux/x86_64/release/a-util.cpp.o
[ 79%]: linking.release main
/usr/local/bin/g++ -o build/linux/x86_64/release/main build/.objs/main/linux/x86_64/release/main.cpp.o -m64 -Lbuild/linux/x86_64/release/a -Lbuild/linux/x86_64/release/b -lutil
/usr/bin/ld: build/.objs/main/linux/x86_64/release/main.cpp.o: in function `main':
main.cpp:(.text+0x1e): undefined reference to `b::util::func()'
collect2: error: ld returned 1 exit status
error: execv(/usr/local/bin/g++ -o build/linux/x86_64/release/main build/.objs/main/linux/x86_64/release/main.cpp.o -m64 -Lbuild/linux/x86_64/release/a -Lbuild/linux/x86_64/release/b -lutil) failed(1)
因为问题的根源并不是namespace中发生了冲突,我认为xmake是正确处理了namespace的,a::util和b::util也能够正确地解析出依赖关系,只是编译中由于basename等发生冲突,在不同目录下生成了同名的.a静态库,最后导致链接时的查找问题
自己 set_filename/set_basename 改下就行了,你 target name 一样,默认的 basename 当然相同了,target 里面不要自己去用 :: 那个是给 namespace 用的,要么你用其他符号。。
自己 set_filename/set_basename 改下就行了,你 target name 一样,默认的 basename 当然相同了,target 里面不要自己去用 :: 那个是给 namespace 用的,要么你用其他符号。。
- 提这个Issue是希望
- 讨论这个target名称冲突的问题,提出feature-request,并给出我的方案设想
- 不是该不该用
set_basename或者target("..")中名称是否规范的问题。无论名称书写是否规范,都是产生了同样的问题——引入namespace后,存在target重名的风险,而文档内似乎是没有明显说明这一点,发生重名时xmake也没有提供明显的提示
- 不采用方案2是因为namespace的设计出发点问题吗?我这边的看法是,如果namespace是为了隔离同名的target, rule等,那我们会希望xmake也“自动”能(或者通过某个policy/rule开启)帮忙避免同名target产生同名输出的问题(这个问题在关闭了intermediate directory后更加明显了,同名输出会互相覆写)
- 关于方案1您怎么看?发生同名target时提醒用户,一是提供一个“双重保险”的作用,二是提升使用/Debug体验,无需翻找文档,一看就能知道问题
不采用方案2是因为namespace的设计出发点问题吗?我这边的看法是,如果namespace是为了隔离同名的target, rule等,那我们会希望xmake也“自动”能(或者通过某个policy/rule开启)帮忙避免同名target产生同名输出的问题(这个问题在关闭了intermediate directory后更加明显了,同名输出会互相覆写)
namespace 已经用了 ::
这种自动不会做,自己手动通过 set_basename 调整,自动处理要处理很多的细节,弄的不好,反而引入更多的坑。
- 如果这两 target 不在一个依赖链上,不会冲突,这个时候不用改名
- 如果一个依赖链上存在冲突,才需要自动改文件名
- 如果自动改了文件名,又会影响
xmake install的安装文件名,到时候用户又是一堆 issues 过来,自动命名不可控,不是所有用户都认可这种需求,有的人不想改,有的认为 xxx-utils.a ,那 xmake 不管怎么自动命名,总会有一部分用户不满足需求会提 issues 过来。
所以还不如用户手动 set_basename 完全可控。
关于方案1您怎么看?发生同名target时提醒用户,一是提供一个“双重保险”的作用,二是提升使用/Debug体验,无需翻找文档,一看就能知道问题
现在最后 link 阶段,linker 本身就会报错,当然前期前期检测报错当然会更友好,但这需求目前优先级不高,等后面有时间也许会考虑。毕竟这种检测本身也会影响性能,尤其在 target 数非常多的时候,为了这极少遇到的 case,每次都要额外去检测一遍,也有点的得不偿失,毕竟 linker 本身也会报错提示。
Bot detected the issue body's language is not English, translate it automatically.
Title: feature-request: resolve or prompt static library generation name conflict
Bot detected the issue body's language is not English, translate it automatically.
Just change set_filename/set_basename yourself. Your target name is the same, and the default basename is of course the same. Don't use it yourself in the target:: That one is for namespace, or you use other symbols. .
Bot detected the issue body's language is not English, translate it automatically.
Just change set_filename/set_basename yourself. Your target name is the same, and the default basename is of course the same. Don’t use it yourself in the target:: That one is for namespace, or you use other symbols. .
- I raise this issue out of hope
- Discuss the problem of target name conflict, raise feature-request, and give my solution idea
- It is not a question of whether
set_basenameshould be used or whether the name intarget("..")is standardized. Regardless of whether the name writing is standardized or not, the same problem arises - after the namespace is introduced, there is a risk of duplicate target names, but this does not seem to be clearly stated in the document, and xmake does not provide an obvious prompt when duplicate names occur.
- Is it because of the design starting point of the namespace that Option 2 is not adopted? My point of view is that if the namespace is to isolate targets, rules, etc. with the same name, then we hope that xmake can also "automatically" (or be turned on through a certain policy/rule) to help avoid the problem of the target with the same name producing output with the same name (this problem becomes more obvious after closing the intermediate directory, and the output with the same name will overwrite each other)
- What do you think about option 1? When a target with the same name occurs, the user is reminded. The first is to provide a "double insurance" effect, and the second is to improve the use/debug experience. There is no need to search for documents, and the problem can be known at a glance.
Bot detected the issue body's language is not English, translate it automatically.
Is it because of the design starting point of the namespace that Option 2 is not adopted? My opinion is that if the namespace is to isolate targets, rules, etc. with the same name, then we hope that xmake can also "automatically" (or be turned on through a certain policy/rule) to help avoid the problem of the target with the same name producing output with the same name (this problem becomes more obvious after closing the intermediate directory, and the output with the same name will overwrite each other)
namespace already used ::
This cannot be done automatically. You have to manually adjust it through set_basename. Automatic processing requires a lot of details. If it is not done well, it will introduce more pitfalls.
- If the two targets are not in the same dependency chain, there will be no conflict, and there is no need to change the name at this time.
- If there is a conflict in a dependency chain, the file name needs to be automatically changed.
- If the file name is automatically changed, it will affect the installation file name of
xmake install. When the time comes, users will have a bunch of issues. Automatic naming is uncontrollable. Not all users agree with this demand. Some people do not want to change it, and some think xxx-utils.a. No matter how xmake automatically names it, there will always be some users who do not meet the needs and will raise issues.
So it is not as fully controllable as manual set_basename by the user.
What do you think about option 1? When a target with the same name occurs, the user is reminded. The first is to provide a "double insurance" effect, and the second is to improve the use/debug experience. There is no need to search for documents, and the problem can be known at a glance.
Now in the final link stage, the linker itself will report an error. Of course, it will be more friendly to detect errors in the early stage. However, this requirement is not a high priority at the moment. We may consider it when we have time later. After all, this kind of detection itself will also affect the performance, especially when the number of targets is very large. For this rarely encountered case, it is necessary to perform an additional detection every time, which is not worth the gain. After all, the linker itself will also report an error message.
其实解决这个问题的最好办法,不是重命名,而是用全路径库文件替代 -L/-l 去做 link ,不过这种方式,不一定所有链接器都支持,我暂时只对 gcc/clang/link.exe 做了支持,可以尝试下这个 patch
https://github.com/xmake-io/xmake/pull/7011
可通过 build.link_target_with_fullpath 策略配置开启或者关闭,目前默认开启了,先观察下兼容性如何,如果不行,就默认关闭,遇到冲突了,手动开。
Bot detected the issue body's language is not English, translate it automatically.
In fact, the best way to solve this problem is not to rename it, but to use the full path library file instead of -L/-l to do link. However, this method may not be supported by all linkers. I only support gcc/clang/link.exe for the time being. You can try this patch.
https://github.com/xmake-io/xmake/pull/7011
It can be turned on or off through the build.link_target_with_fullpath policy configuration. It is currently turned on by default. Check the compatibility first. If not, it will be turned off by default. If there is a conflict, turn it on manually.
其实解决这个问题的最好办法,不是重命名,而是用全路径库文件替代 -L/-l 去做 link ,不过这种方式,不一定所有链接器都支持,我暂时只对 gcc/clang/link.exe 做了支持,可以尝试下这个 patch
可通过
build.link_target_with_fullpath策略配置开启或者关闭,目前默认开启了,先观察下兼容性如何,如果不行,就默认关闭,遇到冲突了,手动开。
这种方式实现上目前还存在不少问题,不太好搞,先放着吧。
Bot detected the issue body's language is not English, translate it automatically.
In fact, the best way to solve this problem is not to rename it, but to use the full path library file instead of -L/-l to do link. However, this method may not be supported by all linkers. I only support gcc/clang/link.exe for the time being. You can try this patch.
It can be turned on or off through the
build.link_target_with_fullpathpolicy configuration. It is currently turned on by default. Check the compatibility first. If not, it will be turned off by default. If there is a conflict, turn it on manually.
There are still many problems in the implementation of this method, which are not easy to solve, so let’s leave it alone for now.