LINUX.ORG.RU

История изменений

Исправление 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/]