// boostdep - a tool to generate Boost dependency reports
//
-// Copyright 2014-2017 Peter Dimov
+// Copyright 2014-2020 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
#include <cstdlib>
#include <streambuf>
#include <sstream>
+#include <cctype>
namespace fs = boost::filesystem;
virtual void header( std::string const & header ) = 0;
};
+static std::string module_for_header( std::string header )
+{
+ {
+ std::map<std::string, std::string>::const_iterator i = s_header_map.find( header );
+
+ if( i != s_header_map.end() )
+ {
+ return i->second;
+ }
+ }
+
+ if( header.substr( 0, 5 ) == "libs/" )
+ {
+ header = header.substr( 5 );
+ }
+ else if( header.substr( 0, 5 ) == "test/" )
+ {
+ header = header.substr( 5 );
+ }
+ else
+ {
+ return std::string();
+ }
+
+ for( std::set<std::string>::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ std::string module = *i;
+ std::replace( module.begin(), module.end(), '~', '/' );
+
+ if( header.substr( 0, module.size() + 1 ) == module + '/' )
+ {
+ return *i;
+ }
+ }
+
+ return std::string();
+}
+
static void output_header_inclusion_report( std::string const & header, header_inclusion_actions & actions )
{
std::string module = s_header_map[ header ];
for( std::set< std::string >::iterator i = from.begin(); i != from.end(); ++i )
{
- from2[ s_header_map[ *i ] ].insert( *i );
+ from2[ module_for_header( *i ) ].insert( *i );
}
for( std::map< std::string, std::set< std::string > >::iterator i = from2.begin(); i != from2.end(); ++i )
for( std::map< std::string, std::set< std::string > >::iterator j = s_header_deps.begin(); j != s_header_deps.end(); ++j )
{
- if( s_header_map[ j->first ] == module )
+ if( module_for_header( j->first ) == module )
{
bool header_started = false;
for( std::set< std::string >::iterator k = j->second.begin(); k != j->second.end(); ++k )
{
- if( s_header_map[ *k ] == *i )
+ if( module_for_header( *k ) == *i )
{
if( !header_started )
{
static void output_module_cmake_report( std::string module )
{
- std::cout << "# Generated by `boostdep --cmake " << module << "`\n\n";
+ std::cout <<
+
+ "# Generated by `boostdep --cmake " << module << "`\n"
+ "# Copyright 2020 Peter Dimov\n"
+ "# Distributed under the Boost Software License, Version 1.0.\n"
+ "# https://www.boost.org/LICENSE_1_0.txt\n"
+ "\n"
+ "cmake_minimum_required(VERSION 3.5...3.16)\n"
+ "\n"
+ ;
std::replace( module.begin(), module.end(), '/', '~' );
+ std::vector<std::string> sources;
+ bool has_c_sources = false;
+
+ fs::path srcpath = module_source_path( module );
+
+ if( fs::exists( srcpath ) )
+ {
+ fs::directory_iterator it( srcpath ), last;
+
+ for( ; it != last; ++it )
+ {
+ if( it->status().type() != fs::regular_file ) continue;
+
+ fs::path p = it->path();
+ std::string ext = p.extension().string();
+
+ if( ext != ".cpp" && ext != ".c" ) continue;
+
+ std::string name = p.filename().string();
+
+ sources.push_back( name );
+
+ if( ext == ".c" ) has_c_sources = true;
+ }
+ }
+
+ std::string lm( module );
+
+ std::replace( lm.begin(), lm.end(), '~', '_' );
+
+ std::cout <<
+
+ "project(boost_" << lm << " VERSION \"${BOOST_SUPERPROJECT_VERSION}\" LANGUAGES" << ( has_c_sources? " C": "" ) << " CXX)\n"
+ "\n"
+ ;
+
collect_primary_dependencies a1;
output_module_primary_report( module, a1, false, false );
- if( !fs::exists( module_source_path( module ) ) )
+ if( !fs::exists( srcpath ) )
{
- for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ // header-only library
+
+ std::cout <<
+
+ "add_library(boost_" << lm << " INTERFACE)\n"
+ "add_library(Boost::" << lm << " ALIAS boost_" << lm << ")\n"
+ "\n"
+ "target_include_directories(boost_" << lm << " INTERFACE include)\n"
+ "\n"
+ ;
+
+ if( !a1.set_.empty() )
{
- std::cout << "boost_declare_dependency(INTERFACE " << module_cmake_name( *i ) << ")\n";
+ std::cout <<
+
+ "target_link_libraries(boost_" << lm << "\n"
+ " INTERFACE\n"
+ ;
+
+ for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ {
+ std::cout << " Boost::" << module_cmake_name( *i ) << "\n";
+ }
+
+ std::cout <<
+
+ ")\n"
+ "\n"
+ ;
}
}
else
{
+ // compiled library
+
+ std::cout <<
+
+ "add_library(boost_" << lm << "\n";
+
+ for( std::vector<std::string>::iterator i = sources.begin(); i != sources.end(); ++i )
+ {
+ std::cout << " src/" << *i << "\n";
+ }
+
+ std::cout <<
+
+ ")\n"
+ "\n"
+ "add_library(Boost::" << lm << " ALIAS boost_" << lm << ")\n"
+ "\n"
+ "target_include_directories(boost_" << lm << " PUBLIC include)\n"
+ "\n"
+ ;
+
collect_primary_dependencies a2;
output_module_primary_report( module, a2, true, false );
- for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ if( !a1.set_.empty() || !a2.set_.empty() )
{
- a2.set_.erase( *i );
- std::cout << "boost_declare_dependency(PUBLIC " << module_cmake_name( *i ) << ")\n";
+ std::cout <<
+
+ "target_link_libraries(boost_" << lm << "\n"
+ ;
+
+ if( !a1.set_.empty() )
+ {
+ std::cout <<
+
+ " PUBLIC\n"
+ ;
+
+ for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ {
+ a2.set_.erase( *i );
+ std::cout << " Boost::" << module_cmake_name( *i ) << "\n";
+ }
+ }
+
+ if( !a2.set_.empty() )
+ {
+ std::cout <<
+
+ " PRIVATE\n"
+ ;
+
+ for( std::set< std::string >::const_iterator i = a2.set_.begin(); i != a2.set_.end(); ++i )
+ {
+ std::cout << " Boost::" << module_cmake_name( *i ) << "\n";
+ }
+ }
+
+ std::cout <<
+
+ ")\n"
+ "\n"
+ ;
}
- std::cout << "\n";
+ std::string um( lm );
- for( std::set< std::string >::const_iterator i = a2.set_.begin(); i != a2.set_.end(); ++i )
+ for( std::string::iterator i = um.begin(); i != um.end(); ++i )
{
- std::cout << "boost_declare_dependency(PRIVATE " << module_cmake_name( *i ) << ")\n";
+ *i = std::toupper( static_cast<unsigned char>( *i ) );
}
+
+ std::cout <<
+
+ "target_compile_definitions(boost_" << lm << "\n"
+ " PUBLIC BOOST_" << um << "_NO_LIB\n"
+ " PRIVATE BOOST_" << um << "_SOURCE\n"
+ ")\n"
+ "\n"
+ "if(BUILD_SHARED_LIBS)\n"
+ " target_compile_definitions(boost_" << lm << " PUBLIC BOOST_" << um << "_DYN_LINK)\n"
+ "else()\n"
+ " target_compile_definitions(boost_" << lm << " PUBLIC BOOST_" << um << "_STATIC_LINK)\n"
+ "endif()\n"
+ "\n"
+ ;
}
+
+ std::cout <<
+
+ "if(BUILD_TESTING AND EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt\")\n"
+ "\n"
+ " add_subdirectory(test)\n"
+ "\n"
+ "endif()\n"
+ "\n"
+ ;
}
// --list-missing-headers