История изменений
Исправление
pavlick,
(текущая версия)
:
Про gcc -M - это не решает задачу, мы увидим включения в file.h, но не в file.cpp, который может включить потомка и мы получим перекрёст (скомпилируется, но возможен deadlock, например).
В общем удвилён, что нет такой простой и нужной утилиты. Набросал свою, а то надоело следить за цифровыми префиксами исходников.
// 0.1.0
// cat Makefile: g++ -std=c++17 -Wall 1.cpp -lstdc++fs
#include <iostream>
#include <vector>
#include <experimental/filesystem>
#include <fstream>
#include <string>
#include <initializer_list>
#include <regex>
#include <algorithm>
namespace fs = std::experimental::filesystem;
using namespace std;
constexpr initializer_list<const char*> header_ext = {".hpp", ".h"};
constexpr initializer_list<const char*> source_ext = {".cpp", ".c"};
struct Unit
{
fs::path name;
vector <const Unit *> deps;
unsigned hierarchy = -1;
};
int main()
{
vector<Unit> units;
for( auto& p: fs::directory_iterator(".") )
if( fs::is_regular_file(p) )
for(const char *head: header_ext)
if(p.path().filename().string().find(head) != string::npos)
{
units.push_back( {p.path().filename()} );
break;
}
auto find_deps = [&units](Unit &p, ifstream &f)
{
string buf;
std::smatch m;
regex reg("[[:space:]]*#[[:space:]]*include[[:space:]]*\"([^/]*)\"");
while( getline(f, buf) )
if( regex_search( buf, m, std::regex(reg)) )
{
if( p.name == fs::path(m[1]) )
continue;
bool found = false;
for(Unit &u: units)
if(u.name == fs::path(m[1]))
{
p.deps.emplace_back(&u);
found = true;
break;
}
if( ! found )
cout << "-----!!!----- INCLUDED FILE "
<< m[1] << " FROM "
<< p.name
<< " IS NOT FOUND\n";
}
};
for(Unit &p: units)
{
ifstream f( p.name.c_str() );
find_deps(p, f);
f.close();
for(const char *src: source_ext)
{
fs::path name_cp = p.name;
name_cp.replace_extension(src);
f.open( name_cp.c_str() );
if( f.is_open() )
{
find_deps(p, f);
break;
}
}
}
if(true)
{
bool progress;
do
{
progress = false;
for(Unit &p: units)
{
if(p.hierarchy != (unsigned)-1)
continue;
unsigned pos = 0;
for(const Unit *u: p.deps)
{
if(u->hierarchy == (unsigned)-1)
{
pos = -1;
break;
}
if(u->hierarchy+1 > pos)
pos = u->hierarchy+1;
}
if(pos != (unsigned)-1)
{
p.hierarchy = pos;
progress = true;
}
}
}
while(progress);
}
for(unsigned cur_hier = -1; ; ++ cur_hier)
{
vector<string> hier_units;
for(Unit &p: units)
{
if(p.hierarchy == cur_hier)
hier_units.emplace_back( p.name.replace_extension() );
}
if( cur_hier != (unsigned)-1 && hier_units.empty() )
break;
if( ! hier_units.empty() )
{
sort( hier_units.begin(), hier_units.end() );
if(cur_hier == (unsigned)-1)
cout << "----!!!!!!---- CROSS REFERENCES ----!!!!!!----\n";
else
cout << "----------------- " << cur_hier << " -----------------\n";
for(const string &str: hier_units)
cout << str << '\n';
}
}
return 0;
}
pavlick@pc ~/ud/test/z $ cat *
//base.h
//child1.cpp
#include "base.h"
#include "child1.h"
//child1.h
//child2.h
#include "base.h"
//child3.h
#include "child1.h"
//child4.cpp
#include "child2.h"
#include "child4.h"
//child4.h
//child5.h
#include "child3.h"
#include "child4.h"
----------------- 0 -----------------
base
----------------- 1 -----------------
child1
child2
----------------- 2 -----------------
child3
child4
----------------- 3 -----------------
child5
Исправление
pavlick,
:
Про gcc -M - это не решает задачу, мы увидим включения в file.h, но не в file.cpp, который может включить потомка и мы получим перекрёст (скомпилируется, но возможен deadlock, например).
В общем удвилён, что нет такой простой и нужной утилиты. Набросал свою, а то надоело следить за цифровыми префиксами исходников.
// 0.1.0
// cat Makefile: g++ -std=c++17 -Wall 1.cpp -lstdc++fs
#include <iostream>
#include <vector>
#include <experimental/filesystem>
#include <fstream>
#include <string>
#include <initializer_list>
#include <regex>
#include <algorithm>
namespace fs = std::experimental::filesystem;
using namespace std;
constexpr initializer_list<const char*> header_ext = {".hpp", ".h"};
constexpr initializer_list<const char*> source_ext = {".cpp", ".c"};
struct Unit
{
fs::path name;
vector <const Unit *> deps;
unsigned hierarchy = -1;
};
int main()
{
vector<Unit> units;
for( auto& p: fs::directory_iterator(".") )
if( fs::is_regular_file(p) )
for(const char *head: header_ext)
if(p.path().filename().string().find(head) != string::npos)
{
units.push_back( {p.path().filename()} );
break;
}
auto find_deps = [&units](Unit &p, ifstream &f)
{
string buf;
std::smatch m;
regex reg("[[:space:]]*#[[:space:]]*include[[:space:]]*\"([^/]*)\"");
while( getline(f, buf) )
if( regex_search( buf, m, std::regex(reg)) )
{
if( p.name == fs::path(m[1]) )
continue;
bool found = false;
for(Unit &u: units)
if(u.name == fs::path(m[1]))
{
p.deps.emplace_back(&u);
found = true;
break;
}
if( ! found )
cout << "-----!!!----- INCLUDED FILE "
<< m[1] << " FROM "
<< p.name
<< " IS NOT FOUND\n";
}
};
for(Unit &p: units)
{
ifstream f( p.name.c_str() );
find_deps(p, f);
f.close();
for(const char *src: source_ext)
{
fs::path name_cp = p.name;
name_cp.replace_extension(src);
f.open( name_cp.c_str() );
if( f.is_open() )
{
find_deps(p, f);
break;
}
}
}
if(true)
{
bool progress;
do
{
progress = false;
for(Unit &p: units)
{
if(p.hierarchy != (unsigned)-1)
continue;
unsigned pos = 0;
for(const Unit *u: p.deps)
{
if(u->hierarchy == (unsigned)-1)
{
pos = -1;
break;
}
if(u->hierarchy+1 > pos)
pos = u->hierarchy+1;
}
if(pos != (unsigned)-1)
{
p.hierarchy = pos;
progress = true;
}
}
}
while(progress);
}
for(unsigned cur_hier = -1; ; ++ cur_hier)
{
vector<string> hier_units;
for(Unit &p: units)
{
if(p.hierarchy == cur_hier)
hier_units.emplace_back( p.name.replace_extension() );
}
if( cur_hier != (unsigned)-1 && hier_units.empty() )
break;
if( ! hier_units.empty() )
{
sort( hier_units.begin(), hier_units.end() );
if(cur_hier == (unsigned)-1)
cout << "----!!!!!!---- CROSS REFERENCES ----!!!!!!----\n";
else
cout << "----------------- " << cur_hier << " -----------------\n";
for(const string &str: hier_units)
cout << str << '\n';
}
}
return 0;
}
pavlick@pc ~/ud/test/z $ cat *
//base.h
//child1.cpp
#include "base.h"
#include "child1.h"
//child1.h
//child2.h
#include "base.h"
#include "child1.h"
//child4.cpp
#include "child2.h"
#include "child4.h"
//child4.h
//child5.h
#include "child3.h"
#include "child4.h"
----------------- 0 -----------------
base
----------------- 1 -----------------
child1
child2
----------------- 2 -----------------
child3
child4
----------------- 3 -----------------
child5
Исходная версия
pavlick,
:
Про gcc -M - это не решает задачу, мы увидим включения в file.h, но не в file.cpp, который может включить потомка и мы получим перекрёст (скомпилируется, но возможен deadlock, например).
В общем удвилён, что нет такой простой и нужной утилиты. Набросал свою, а то надоело следить за цифровыми префиксами исходников.
// 0.1.0
// cat Makefile: g++ -std=c++17 -Wall 1.cpp -lstdc++fs
#include <iostream>
#include <vector>
#include <experimental/filesystem>
#include <fstream>
#include <string>
#include <initializer_list>
#include <regex>
#include <algorithm>
namespace fs = std::experimental::filesystem;
using namespace std;
constexpr initializer_list<const char*> header_ext = {".hpp", ".h"};
constexpr initializer_list<const char*> source_ext = {".cpp", ".c"};
struct Unit
{
fs::path name;
vector <const Unit *> deps;
unsigned hierarchy = -1;
};
int main()
{
vector<Unit> units;
for( auto& p: fs::directory_iterator(".") )
if( fs::is_regular_file(p) )
for(const char *head: header_ext)
if(p.path().filename().string().find(head) != string::npos)
{
units.push_back( {p.path().filename()} );
break;
}
auto find_deps = [&units](Unit &p, ifstream &f)
{
string buf;
std::smatch m;
regex reg("[[:space:]]*#[[:space:]]*include[[:space:]]*\"([^/]*)\"");
while( getline(f, buf) )
if( regex_search( buf, m, std::regex(reg)) )
{
if( p.name == fs::path(m[1]) )
continue;
bool found = false;
for(Unit &u: units)
if(u.name == fs::path(m[1]))
{
p.deps.emplace_back(&u);
found = true;
break;
}
if( ! found )
cout << "-----!!!----- INCLUDED FILE "
<< m[1] << " FROM "
<< p.name
<< " IS NOT FOUND\n";
}
};
for(Unit &p: units)
{
ifstream f( p.name.c_str() );
find_deps(p, f);
f.close();
for(const char *src: source_ext)
{
fs::path name_cp = p.name;
name_cp.replace_extension(src);
f.open( name_cp.c_str() );
if( f.is_open() )
{
find_deps(p, f);
break;
}
}
}
if(true)
{
bool progress;
do
{
progress = false;
for(Unit &p: units)
{
if(p.hierarchy != (unsigned)-1)
continue;
unsigned pos = 0;
for(const Unit *u: p.deps)
{
if(u->hierarchy == (unsigned)-1)
{
pos = -1;
break;
}
if(u->hierarchy+1 > pos)
pos = u->hierarchy+1;
}
if(pos != (unsigned)-1)
{
p.hierarchy = pos;
progress = true;
}
}
}
while(progress);
}
for(unsigned cur_hier = -1; ; ++ cur_hier)
{
vector<string> hier_units;
for(Unit &p: units)
{
if(p.hierarchy == cur_hier)
hier_units.emplace_back( p.name.replace_extension() );
}
if( cur_hier != (unsigned)-1 && hier_units.empty() )
break;
if( ! hier_units.empty() )
{
sort( hier_units.begin(), hier_units.end() );
if(cur_hier == (unsigned)-1)
cout << "----!!!!!!---- CROSS REFERENCES ----!!!!!!----\n";
else
cout << "----------------- " << cur_hier << " -----------------\n";
for(const string &str: hier_units)
cout << str << '\n';
}
}
return 0;
}
pavlick@pc ~/ud/test/z $ cat *
//base.h
//child1.cpp
#include "base.h"
#include "child1.h"
//child1.h
//child2.h
#include "base.h"
#include "child1.h"
//child4.cpp
#include "child2.h"
#include "child4.h"
//child4.h
//child5.h
#include "child3.h"
#include "child4.h"
----------------- 0 -----------------
base
----------------- 1 -----------------
child1
child2
----------------- 2 -----------------
child3
child4
----------------- 3 -----------------
child5
[code/]