Same file is reported multiple times when relative paths are used
i-ky opened this issue · comments
Here is the output I've got when analyzing one project:
*** Expensive headers:
4826 ms: ../../../include/common.h (included 82 times, avg 58 ms), included via:
...
1657 ms: ../../../../include/common.h (included 28 times, avg 59 ms), included via:
...
938 ms: ../../include/common.h (included 16 times, avg 58 ms), included via:
...
This is actually the same header and in the project it is always included via
#include "common.h"
Project folder structure looks like this:
├ include/
└ src/
└ foo/
└ bar/
└ baz/
... with each directory having its own Makefile
listing subdirectories and make
is called recursively. Top-level make
gets -Iinclude
and down the line we get -I../include
, -I../../include
, etc.
I think ClangBuildAnalyzer
should report either absolute paths to files or paths relative to its working directory combining paths from *.json
files and relative locations of *.json
files themselves. Path fragments like <some directory>/../
should be squashed.
I suspect the issue might be due to different working directories used during the build (due to recursive makefiles). But kinda hard to say. Would help if you could attach your .json files produced during the build.
I suspect the issue might be due to different working directories used during the build (due to recursive makefiles).
Yes, I think this is exactly what happens.
Would help if you could attach your .json files produced during the build.
I've done some analysis. I hope the following one-liner illustrates the situation.
find -name '*.json'
looks for JSON files,dirname $file
gets the directory where file is located,jq --raw-output '.traceEvents[] | select(.args.detail | . and contains("/include/common.h")) | .args.detail' $file
looks for inclusions of common.h in JSON,echo .../...
concatenates both paths,sort
anduniq
remove duplicates.
So, here are locations of JSON files concatenated with relative path to common.h header(s) they include:
$ for file in $(find -name '*.json'); do echo `dirname $file`/`jq --raw-output '.traceEvents[] | select(.args.detail | . and contains("/include/common.h")) | .args.detail' $file`; done | sort | uniq
./src/libs/zbxalgo/../../../include/common.h
./src/libs/zbxcommon/../../../include/common.h
./src/libs/zbxcommshigh/../../../include/common.h
./src/libs/zbxcomms/../../../include/common.h
./src/libs/zbxcompress/../../../include/common.h
./src/libs/zbxconf/../../../include/common.h
./src/libs/zbxcrypto/../../../include/common.h
./src/libs/zbxdbcache/../../../include/common.h
./src/libs/zbxdbhigh/../../../include/common.h
./src/libs/zbxdb/../../../include/common.h
./src/libs/zbxdbupgrade/../../../include/common.h
./src/libs/zbxembed/
./src/libs/zbxembed/../../../include/common.h
./src/libs/zbxexec/../../../include/common.h
./src/libs/zbxhistory/../../../include/common.h
./src/libs/zbxhttp/../../../include/common.h
./src/libs/zbxicmpping/../../../include/common.h
./src/libs/zbxipcservice/../../../include/common.h
./src/libs/zbxjson/../../../include/common.h
./src/libs/zbxlog/../../../include/common.h
./src/libs/zbxmedia/../../../include/common.h
./src/libs/zbxmemory/../../../include/common.h
./src/libs/zbxmodules/../../../include/common.h
./src/libs/zbxnix/../../../include/common.h
./src/libs/zbxprometheus/../../../include/common.h
./src/libs/zbxregexp/../../../include/common.h
./src/libs/zbxself/../../../include/common.h
./src/libs/zbxserver/../../../include/common.h
./src/libs/zbxsys/../../../include/common.h
./src/libs/zbxsysinfo/agent/../../../../include/common.h
./src/libs/zbxsysinfo/common/../../../../include/common.h
./src/libs/zbxsysinfo/../../../include/common.h
./src/libs/zbxsysinfo/linux/../../../../include/common.h
./src/libs/zbxsysinfo/simple/../../../../include/common.h
./src/libs/zbxtasks/../../../include/common.h
./src/zabbix_agent/../../include/common.h
./src/zabbix_get/../../include/common.h
./src/zabbix_proxy/datasender/../../../include/common.h
./src/zabbix_proxy/heart/../../../include/common.h
./src/zabbix_proxy/housekeeper/../../../include/common.h
./src/zabbix_proxy/../../include/common.h
./src/zabbix_proxy/proxyconfig/../../../include/common.h
./src/zabbix_proxy/taskmanager/../../../include/common.h
./src/zabbix_sender/../../include/common.h
./src/zabbix_server/alerter/../../../include/common.h
./src/zabbix_server/dbconfig/../../../include/common.h
./src/zabbix_server/dbsyncer/../../../include/common.h
./src/zabbix_server/discoverer/../../../include/common.h
./src/zabbix_server/escalator/../../../include/common.h
./src/zabbix_server/housekeeper/../../../include/common.h
./src/zabbix_server/httppoller/../../../include/common.h
./src/zabbix_server/../../include/common.h
./src/zabbix_server/ipmi/../../../include/common.h
./src/zabbix_server/lld/../../../include/common.h
./src/zabbix_server/odbc/../../../include/common.h
./src/zabbix_server/pinger/../../../include/common.h
./src/zabbix_server/poller/../../../include/common.h
./src/zabbix_server/preprocessor/../../../include/common.h
./src/zabbix_server/proxypoller/../../../include/common.h
./src/zabbix_server/scripts/../../../include/common.h
./src/zabbix_server/selfmon/../../../include/common.h
./src/zabbix_server/snmptrapper/../../../include/common.h
./src/zabbix_server/taskmanager/../../../include/common.h
./src/zabbix_server/timer/../../../include/common.h
./src/zabbix_server/trapper/../../../include/common.h
./src/zabbix_server/vmware/../../../include/common.h
As you see, if we squash ..
with the directory on the left (recursively) we will always get ./include/common.h
.
Same here. Built with ninja though, i.e. no recursive makefiles.
../src/f1/f2/../../f1/f2/file.h
../src/f1/f3/../../f1/f2/file.h
PoC fix:
#include <filesystem>
namespace fs = std::filesystem;
std::string utils::GetNicePath(const std::string_view& path)
{
return fs::path(path).lexically_normal();
}