Skip to content

[Bug] 关于framework和include的处理的bug #4597

@debugee

Description

@debugee

Brief Issue Summary

这些bug是关于cmake、vscode-cmake-tools、cpptools在处理framework和include的路径的若干问题

1、我们先创建一个测试工程bug-sample,工程文件如下

Image

2、我们要知道搜索路径的优先级(同级别的标志设置的路径,谁在前面谁先优先级高)
-I(或者-F) 添加的路径,
-isystem 添加的路径
-iframework 添加的路径
编译器默认路径(c++头文件、编译器内置的头文件、c头文件、工具链额外头文件 、还有默认的sdk framework路径)
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1
/Library/Developer/CommandLineTools/usr/lib/clang/16/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)

3、我们对搜索路径优先级做一下测试
编译命令:clang -F /Users/admin/Desktop/bug-sample/build -I /Users/admin/Desktop/bug-sample/abc sample.cpp -c -v
输出:
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
/Users/admin/Desktop/bug-sample/build (framework directory)
/Users/admin/Desktop/bug-sample/abc
/usr/local/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1
/Library/Developer/CommandLineTools/usr/lib/clang/16/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
In file included from sample.cpp:3:
/Users/admin/Desktop/bug-sample/build/dynamicFramework.framework/Headers/dynamicFramework.h:1:9: warning: framework dir dynamicFramework.h [-W#pragma-messages]
1 | #pragma message ("framework dir dynamicFramework.h")
| ^
1 warning generated.
我们看到sample.cpp中包含的头文件用的是framework目录中的,因为 -F 在 -I前面

编译命令:clang -I /Users/admin/Desktop/bug-sample/abc -F /Users/admin/Desktop/bug-sample/build sample.cpp -c -v
输出:
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
/Users/admin/Desktop/bug-sample/abc
/Users/admin/Desktop/bug-sample/build (framework directory)
/usr/local/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1
/Library/Developer/CommandLineTools/usr/lib/clang/16/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
In file included from sample.cpp:3:
/Users/admin/Desktop/bug-sample/abc/dynamicFramework/dynamicFramework.h:1:9: warning: abc dynamicFramework.h [-W#pragma-messages]
1 | #pragma message ("abc dynamicFramework.h")
| ^
1 warning generated.

我们把 -I和-F换位置之后,sample.cpp使用的是abc目录中的dynamicFramework.h文件

Image

-isystem 添加的路径 在 -I添加的路径 的后面
-iframework 添加的路径 在 -isystem添加的路径 的后面 (就算-iframework 标志在 -isystem 前面设置)
我们看到clang还会添加一个默认的/user/local/include (-I级别)

4、好了,我们知道编译器逻辑之后,我们在看看cmake、cmake-tools、cpptools是如何处理错误的
首先我会列出来我使用的各个插件、cmake、vscode等的版本信息,(我保证新版本也有问题,我也测试过新版本)
cpptools: 1.28.3
cmaketools: 1.19.52
vscode:
Version: 1.102.3
Commit: 488a1f239235055e34e673291fb8d8c810886f81
Date: 2025-07-29T03:00:23.339Z
Electron: 35.6.0
ElectronBuildId: 11847422
Chromium: 134.0.6998.205
Node.js: 22.15.1
V8: 13.4.114.21-electron.0
OS: Darwin x64 23.6.0
cmake:3.31.5

5、cmake会生产一些json给cmake-tools使用,cmake-tools使用它来配置cpptools

Image 我们看到生成了frameworks, 通过下面的讨论链接,说是解决frameworks无法找到头文件的问题,实际并没有处理好 [1](https://github.com//pull/3247) [2](https://github.com//issues/2324) [3](https://gitlab.kitware.com/cmake/cmake/-/commit/b3a6a11e95f805ab7411d395bd426561cfb4d4d0) 实际处理逻辑是 参考cmake代码

/Users/admin/cmake-3.31.5/Source/cmFileAPICodemodel.cxx
Image

Image

我们看到cmake通过判断includePathList 表中的路径尾部是不是.framework然后把includePathList分成2部分存放到json中,分别是Frameworks和Includes
这样处理会丢失了优先级吗?

一般是不会的,因为cmake 最后处理framework类型的引入,前面先引入include_directories和interface_include_directories (继承)
Image

不管是这样引入framework
target_link_libraries(sample PRIVATE /Users/admin/Desktop/bug-sample/build/dynamicFramework.framework/dynamicFramework)
还是这样引入
target_link_libraries(sample PRIVATE dynamicFramework)
都会最后处理,并添加一个/Users/admin/Desktop/bug-sample/build/dynamicFramework.framework路径到includes路径中.

并生成CXX_INCLUDES到build/CMakeFiles/flag.cmake中.
然后cmake还会生成CXX_FLAGS到build/CMakeFiles/flag.cmake中,
手动添加的路径(-I 或者 -iframework或者-F),例如target_compile_options(sample PRIVATE -I/Users/admin)
会反应到CXX_FLAGS 上或者cmake fileapi中的json 中类似

Image Image Image

并且cmake-tools是直接把Frameworks附加在Includes后面

/Users/admin/Downloads/vscode-cmake-tools-main/src/cpptools.ts

Image

也就是说includes是分cxx_includes部分和cxx_flags部分,是分开处理的,并由cmake-tools投递给cpptools使用

===========
问题1、cmake-tools 把framework当简单的include使用,导致cpptools在#include <framework/xxxxx.h>类型的识别有问题.
我们看看这个链接的问题
https://github.com/microsoft/vscode-cmake-tools/issues/2324.其实并没有处理好这个问题,因为framework被当作include使用了.

#include 可以正常goto,因为qt的cmake文件全路径/Users/admin/Qt/6.7.2/macos/lib/QtWidgets.framework/Headers会添加INTERFACE_INCLUDE_DIRECTORIES到
这里注意还添加了一个/Users/admin/Qt/6.7.2/macos/lib/QtWidgets.framework到INTERFACE_INCLUDE_DIRECTORIES中,这里会导致优先级错误
Image

Image

如果我们这样
add_library(test INTERFACE)
set_target_properties(test PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "/Users/admin/Desktop/bug-sample/build/dynamicFramework.framework;/Users/admin/Desktop/bug-sample/build/dynamicFramework.framework/Headers"
)
就会导致这样的优先级

Image 显然-F不再是cxx_includes的尾部 Image 但是cmake把Frameworks从Includes分离出来了,显然优先级信息丢失了. cmake-tools又直接把Frameworks添加到includes的尾部,显然 [build] /Users/admin/Desktop/bug-sample/build (framework directory) 和 [build] /Users/admin/Desktop/bug-sample/build/dynamicFramework.framework/Headers 的顺序会错误.

并且这里面还隐藏这一个cpptools的问题,前面的链接里面没人发现问题的根本

Image 我们先手动解决一下framework路径/users/admin/qt/6.7.2/macos/lib被当作include使用的问题 Image 但是从main.cpp到QMessageBox没问题,从QMessageBox到qmessagebox.h也没有问题 进入qmessagebox.h就有问题了 因为QMessageBox没有文件后缀,导致后面的goto动作,把QMessageBox当作一个cpp源文件,而这个文件没有在工程的sources 中,也就没有编译参数,然后就出错了,简单点, QMessageBox是一个新的Translation unit Image

好了,设计一开始就是不对的,导致优先级存在问题,cmake-tools直接把framework当include使用的错误,cpptools解析单元跟踪丢失

问题2、cxx_flags部分手动-I添加的路径应该在cxx_includes部分中 -isystem和-iframework添加的路径的前面,因为这种设计导致,cpptools根本不可能知道正确的优先级

Image Image 编译命令: { "directory": "/Users/admin/Desktop/bug-sample/build", "command": "/usr/bin/clang++ -I/Users/admin/Desktop/bug-sample/abc -I/Users -iframework /Users/admin/Desktop/bug-sample/build -g -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX15.2.sdk -mmacosx-version-min=14.6 -v -I/Users/admin -o CMakeFiles/sample.dir/sample.cpp.o -c /Users/admin/Desktop/bug-sample/sample.cpp", "file": "/Users/admin/Desktop/bug-sample/sample.cpp", "output": "CMakeFiles/sample.dir/sample.cpp.o" } 正确的应该是/Users/admin在/Users/admin/Desktop/bug-sample/build前面

CMake Tools Diagnostics

.

Debug Log

.

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    buga bug in the product

    Type

    No type

    Projects

    Status

    Completed

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions