/usr/local/include 无意中添加到我的编译命令导致构建失败
/usr/local/include unintendedly added to my compile commands results in build failing
背景
我正在一台运行 macOS 10.15 的机器上编译一个项目,该项目将旧版本的 libpng (1.6.17) 作为子模块提供。相应的代码可在 https://github.com/glennrp/libpng 获得。我还安装了 Homebrew 的 libpng 1.6.37。
直到不久前,我还能够使用 CMake 轻松编译 libpng 1.6.17。从最近开始(但我不知道确切日期),构建失败并出现如下错误:
FAILED: CMakeFiles/png16_static.dir/pngwutil.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -I/usr/local/include -I. -I../ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -MD -MT CMakeFiles/png16_static.dir/pngwutil.o -MF CMakeFiles/png16_static.dir/pngwutil.o.d -o CMakeFiles/png16_static.dir/pngwutil.o -c ../pngwutil.c
../pngwutil.c:2413:20: error: use of undeclared identifier 'PNG_WEIGHT_SHIFT'
PNG_WEIGHT_SHIFT;
^
我 运行 对我的项目副本进行了一些检查,该副本仍然正确编译,因为 CMake 本身不在其中 re-running。这两种情况之间的唯一区别是编译器调用中添加了 -I/usr/local/include
标志(我添加了一些标记以帮助查看区别):
- 成功:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -Dpng16_EXPORTS -Iext_build/libpng -I../../ext/libpng -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -fPIC -fno-stack-protector -fomit-frame-pointer -fno-math-errno -ffp-contract=fast -march=native -MD -MT ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -MF ext_build/libpng/CMakeFiles/png16.dir/pngrio.o.d -o ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -c ../../ext/libpng/pngrio.c
<---------------------------------->
- 失败:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -Dpng16_EXPORTS -I/usr/local/include -Iext_build/libpng -I../../ext/libpng -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -fPIC -fno-stack-protector -fomit-frame-pointer -fno-math-errno -ffp-contract=fast -march=native -MD -MT ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -MF ext_build/libpng/CMakeFiles/png16.dir/pngrio.o.d -o ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -c ../../ext/libpng/pngrio.c
<------------------------------------------------------->
我在正在运行的项目副本上 re-ran CMake,但我遇到了同样的错误,这让我遇到了 system-related 问题。然后我直接检查了 libpng 源并得到了同样的错误。
重现步骤
- 克隆 libpng 存储库并检查 v1.6.17
git clone https://github.com/glennrp/libpng.git
cd libpng
git checkout v1.6.17
- 建立libpng
cmake . -B build && cmake --build build
问题
什么将这个 -I/usr/local/include
标志添加到我的编译器调用中?
奖金问题(可能更有趣)
现在,它变得有趣了。如果您签出更新的 libpng(我尝试使用 1.6.21、1.6.25、1.6.28、1.6.33 和 1.6.37),问题就会消失,尽管标志仍然存在:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -I/usr/local/include -I. -I../ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -MD -MT CMakeFiles/png16_static.dir/pngrio.o -MF CMakeFiles/png16_static.dir/pngrio.o.d -o CMakeFiles/png16_static.dir/pngrio.o -c ../pngrio.c
这意味着我可以使用这些版本之一更新我的子模块,我的问题就会消失。
但是,如果我没记错的话,-I
标志是从左到右解析的:因此我怀疑使用了我的 Homebrew headers 而不是源代码。如果我是对的,那么这并不能保证 libpng 的 Homebrew 升级不会再次破坏构建:它只是表明 libpng 的 API 自 v1.6.21 以来一直稳定并且我可以将 Homebrew headers 与我尝试编译的源一起使用。我是对的,还是我漏掉了什么?
- 问题回答:系统包含路径由compiler/preprocessor添加(this page将解释更多数据)
- 包含在CMake项目中的顺序可能会改变(不确定多少),CMake允许在列表中预先包含;尝试比较版本之间的 CMake 构建脚本。相信会有提到的变化。
是的,有时 cmake 会选择各种库并包含目录并自由混合和匹配。如果你需要保持多个版本,你应该使用 cmake 命令来传递正确的包。
我终于弄明白了。结果是 libpng 的 zlib 依赖项给我带来了麻烦(间接)。
发生了什么事
MacOS 附带 zlib,开发人员通常都知道它,因此觉得不需要安装第 3 方 zlib。然而,CMake 的 find_package
不知道这个偏好,并且会选择在 /usr/local
中找到的 zlib 实现,例如,如果它是由 Homewbrew 安装的。出于某种原因,第 3 方软件在我系统的这个位置安装了一个 zlib,而不是 Homebrew 包,这使得检测更加困难,它被 find_package
.
检测到
对应的include目录为/usr/local/include
。 libpng 的 CMake 代码是这样的,这个目录然后被添加到包含目录的列表中,这导致了问题中提到的 header 冲突。我通过 CMakeCache.txt
(搜索 /usr/local/include
)了解发生了什么,所以主要的教训是:在这种情况下不要忘记检查您的 CMake 缓存.
如何解决问题
懒惰的方式。删除不需要的 lib 文件。我 运行 brew doctor
并删除了不应该在此处的文件。但是,如果某些软件实际上需要 /usr/local
中的特定 zlib 版本,这可能会产生不良后果。
肮脏的 CMake 方式。修改 top-level CMake 代码以提示 find_package
它应该选择 zlib 的位置。使用 PATHS
参数 hard-code 提示或使用 ZLIB_ROOT
参数设置提示(您可能必须为此定义策略)。
我确信有更好的方法可以通过在 libpng 中 "doing CMake right" 和在系统路径中强制库搜索来处理这个问题,但我的 CMake 技能不足以说明应该做什么。不管怎样,关于这个问题有点off-topic。
背景
我正在一台运行 macOS 10.15 的机器上编译一个项目,该项目将旧版本的 libpng (1.6.17) 作为子模块提供。相应的代码可在 https://github.com/glennrp/libpng 获得。我还安装了 Homebrew 的 libpng 1.6.37。
直到不久前,我还能够使用 CMake 轻松编译 libpng 1.6.17。从最近开始(但我不知道确切日期),构建失败并出现如下错误:
FAILED: CMakeFiles/png16_static.dir/pngwutil.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -I/usr/local/include -I. -I../ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -MD -MT CMakeFiles/png16_static.dir/pngwutil.o -MF CMakeFiles/png16_static.dir/pngwutil.o.d -o CMakeFiles/png16_static.dir/pngwutil.o -c ../pngwutil.c
../pngwutil.c:2413:20: error: use of undeclared identifier 'PNG_WEIGHT_SHIFT'
PNG_WEIGHT_SHIFT;
^
我 运行 对我的项目副本进行了一些检查,该副本仍然正确编译,因为 CMake 本身不在其中 re-running。这两种情况之间的唯一区别是编译器调用中添加了 -I/usr/local/include
标志(我添加了一些标记以帮助查看区别):
- 成功:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -Dpng16_EXPORTS -Iext_build/libpng -I../../ext/libpng -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -fPIC -fno-stack-protector -fomit-frame-pointer -fno-math-errno -ffp-contract=fast -march=native -MD -MT ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -MF ext_build/libpng/CMakeFiles/png16.dir/pngrio.o.d -o ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -c ../../ext/libpng/pngrio.c <---------------------------------->
- 失败:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -Dpng16_EXPORTS -I/usr/local/include -Iext_build/libpng -I../../ext/libpng -O3 -DNDEBUG -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -fPIC -fno-stack-protector -fomit-frame-pointer -fno-math-errno -ffp-contract=fast -march=native -MD -MT ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -MF ext_build/libpng/CMakeFiles/png16.dir/pngrio.o.d -o ext_build/libpng/CMakeFiles/png16.dir/pngrio.o -c ../../ext/libpng/pngrio.c <------------------------------------------------------->
我在正在运行的项目副本上 re-ran CMake,但我遇到了同样的错误,这让我遇到了 system-related 问题。然后我直接检查了 libpng 源并得到了同样的错误。
重现步骤
- 克隆 libpng 存储库并检查 v1.6.17
git clone https://github.com/glennrp/libpng.git cd libpng git checkout v1.6.17
- 建立libpng
cmake . -B build && cmake --build build
问题
什么将这个 -I/usr/local/include
标志添加到我的编译器调用中?
奖金问题(可能更有趣)
现在,它变得有趣了。如果您签出更新的 libpng(我尝试使用 1.6.21、1.6.25、1.6.28、1.6.33 和 1.6.37),问题就会消失,尽管标志仍然存在:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -I/usr/local/include -I. -I../ -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -MD -MT CMakeFiles/png16_static.dir/pngrio.o -MF CMakeFiles/png16_static.dir/pngrio.o.d -o CMakeFiles/png16_static.dir/pngrio.o -c ../pngrio.c
这意味着我可以使用这些版本之一更新我的子模块,我的问题就会消失。
但是,如果我没记错的话,-I
标志是从左到右解析的:因此我怀疑使用了我的 Homebrew headers 而不是源代码。如果我是对的,那么这并不能保证 libpng 的 Homebrew 升级不会再次破坏构建:它只是表明 libpng 的 API 自 v1.6.21 以来一直稳定并且我可以将 Homebrew headers 与我尝试编译的源一起使用。我是对的,还是我漏掉了什么?
- 问题回答:系统包含路径由compiler/preprocessor添加(this page将解释更多数据)
- 包含在CMake项目中的顺序可能会改变(不确定多少),CMake允许在列表中预先包含;尝试比较版本之间的 CMake 构建脚本。相信会有提到的变化。
是的,有时 cmake 会选择各种库并包含目录并自由混合和匹配。如果你需要保持多个版本,你应该使用 cmake 命令来传递正确的包。
我终于弄明白了。结果是 libpng 的 zlib 依赖项给我带来了麻烦(间接)。
发生了什么事
MacOS 附带 zlib,开发人员通常都知道它,因此觉得不需要安装第 3 方 zlib。然而,CMake 的 find_package
不知道这个偏好,并且会选择在 /usr/local
中找到的 zlib 实现,例如,如果它是由 Homewbrew 安装的。出于某种原因,第 3 方软件在我系统的这个位置安装了一个 zlib,而不是 Homebrew 包,这使得检测更加困难,它被 find_package
.
对应的include目录为/usr/local/include
。 libpng 的 CMake 代码是这样的,这个目录然后被添加到包含目录的列表中,这导致了问题中提到的 header 冲突。我通过 CMakeCache.txt
(搜索 /usr/local/include
)了解发生了什么,所以主要的教训是:在这种情况下不要忘记检查您的 CMake 缓存.
如何解决问题
懒惰的方式。删除不需要的 lib 文件。我 运行 brew doctor
并删除了不应该在此处的文件。但是,如果某些软件实际上需要 /usr/local
中的特定 zlib 版本,这可能会产生不良后果。
肮脏的 CMake 方式。修改 top-level CMake 代码以提示 find_package
它应该选择 zlib 的位置。使用 PATHS
参数 hard-code 提示或使用 ZLIB_ROOT
参数设置提示(您可能必须为此定义策略)。
我确信有更好的方法可以通过在 libpng 中 "doing CMake right" 和在系统路径中强制库搜索来处理这个问题,但我的 CMake 技能不足以说明应该做什么。不管怎样,关于这个问题有点off-topic。