Boost logo

Boost :

Subject: Re: [boost] Announcement: Faber, a new build system based on bjam
From: Domen Vrankar (domen.vrankar_at_[hidden])
Date: 2017-12-02 23:50:43


2017-12-02 22:34 GMT+01:00 Stefan Seefeld <stefan_at_[hidden]>:

> Hi Domen,
>
> On 02.12.2017 15:58, Domen Vrankar wrote:
>
> Stefan I have one suggestion - maybe a stupid one but that's for you to
> decide...
>
> Since Faber is meant to be a cross platform build system and CMake is a
> build system generator you could perhaps start by competing with other
> build systems by attempting to integrate Faber into CMake as yet another
> build system along side Makefiles, Ninja...
>
>
> What would be the point of that ? Do CMake users really care what build
> system "backend" is being used ? I thought the goal was for them to only
> interact with CMake itself ?
>

In this thread I've read that a build system is better than a meta build
system as it removes one layer of complexity - and that one extra layer is
a really problematic part or something like that:

> Yes. But despite its popularity, I disagree with CMake's approach on a
> very fundamental level (it being a build system generator, rather than a
> build system), as it makes things oh so much more complex. Everything
> works well until it doesn't, at which point all hell breaks loose.
> That's very typical for macro-based languages (think latex, m4). And it
> had to reinvent its own language, in a rather ad-hoc manner (i.e.
> started with a simple declarative syntax, but then had to expand on that
> to cover other use-cases. "Now you have two problems." comes to mind (if
> I may paraphrase).

Most of the time when using CMake I don't care which build system is used -
most of the time I even don't care which compiler or operating system it is
used on. So the advantage of having a true build system rather than a meta
build system is lost on me in 99% of the cases.

Which brings us to:

>
> I expect Faber to get most publicity from its simple and portable
> interface, which wouldn't even be visible if it were used as a CMake
> backend. Moreover, CMake as a build script generator produces extremely
> ugly and unreadable Makefiles. That's in the nature of the approach of a
> macro-language. The Makefile has degenerated into an intermediate
> representation, not something for a human eye to dwell on. Doing that with
> Faber would be entirely pointless, I think.
>

I had to look at the generated Makefiles 3 or 4 times in the past 8 years
so it's nice to see something at least a bit familiar there - but doesn't
really matter as usually I just have to look at the line in the generated
file that failed and more often than not that line is quite readable as it
just calls compiler with certain flags or some external program.

So with Faber I would expect to see generated file with:
gxx11 = gxx(name='g++11', features=cxxflags('--std=c++11'))
hello = binary('hello', 'hello.cpp')

Which would possibly be simpler to read.

And for now this is the only "advantage" that I see with a build system
that does the abstraction job of CMake compared to using Makefiles in
combination with a meta build system...

I'm simply trying to see the benefits in Feber and unfortunately that's the
most that I came up with... That's why I suggested the integration attempt.
I was hoping that you could see a benefit in such a merger that would go
beyond reimplementing CMake with a bit different syntax and less
abstraction from what I can see from Feber's docs. I'm trying to see in
Feber what you see to make it worth your development time and to be honest
after going through the documentation and this thread I'm failing to see
it. Your reply just added to my doubts because if the only two benefits are
not generating intermediate build files which I extremely rarely look at
and a bit (and I mean just a bit) different syntax that simply doesn't cut
it for me...

In case you'd manage to integrate it into CMake as a back-end that could
become the only non-legacy back-end for C++ on all platforms in a couple of
years that would possibly make this something more than a "reimplementation
of CMake with a small new twist".

Though I may misunderstand either what you are suggesting, or even the
> way(s) in which users use CMake.
>

I really hate the logic of spawning new computer languages with one new
feature just for the sake of it really annoying as it makes my life
considerably harder (hype driven development logic...) and same goes for
reinventing the tools with only minor differences but with a large impact
on the code ecosystem fragmentation. On the other hand I'm trying to keep
an open mind as much as possible and that was my main reason for the
suggestion. If CMake wouldn't exist and wouldn't have its fair share of the
market I'd say that Feber is a great idea on its own but as it stands I
don't see it as an advancement but more as a hype-because-I-can thing that
would just fragment a small portion the landscape a bit further making my
life harder while not adding any great change. I would really like to see
in it what you obviously manage to see...

> C++ evolved on top of C, CMake evolved on top of existing build systems so
> I don't find it a bad idea to hitch a ride on CMake with Faber and improve
> them both by doing that.
>
>
> Not everyone agrees that it was to C++'s advantage that it was (initially)
> promoted as "C with objects". But let's not digress.
> I'm (obviously) not against the idea of layering new frontends over Faber.
> In fact, I have designed it to be usable as a library, precisely so people
> can extend Faber with frontends (for example graphical ones).
> But I think I'd spend my time more wisely focusing on Faber itself, its
> missing features, documentation, etc., and let those who like working with
> CMake add and improve bindings to build system backends.
>

http://www.stroustrup.com/bs_faq.html#whyC

Opinions differ but my point was just the "C++ would have been stillborn."
part. But everybody sees things from their own perspective and only the
time tells which choices were feasible enough to make something survive.

For the end I'd like to give you an example how most of my CMakeLists.txt
files look like (they are quite similar but most of the time on a more
abstract level if at all possible than what Feber does):

#--------------------
cmake_minimum_required(VERSION "3.10.0" FATAL_ERROR)

set(CMAKE_CXX_STANDARD 14)

# search for dependencies
find_package(x1 1.2 REQUIRED CONFIG) # some package supporting cmake import
targets
find_package(Boost REQUIRED) # some package for which somebody provided a
find module (find Boost module is messy as Boost doesn't export a CMake
friendly targets file but at least it's provided by CMake out of the box...)

# add sub projects/components
add_subdirectory(subproject_1)

# build a library
add_library(my_lib SHARED
  lib_stuff.cpp
  lib_stuff_2.cpp)
target_include_directories(project_2_lib
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:my_project/include>
  )

# build executable
add_executable(my_fancy_exe
   file.cpp
   some_other_file.cpp
)
target_link_libraries(
  my_fancy_exe
  PRIVATE
    x1::some_component_3
    x1::some_component_x
    Boost::asio
    my_lib
)

# install locations and stuff
install(TARGETS my_fancy_exe my_fancy_lib
  EXPORT my-config
  RUNTIME DESTINATION my/bin COMPONENT bin
  LIBRARY DESTINATION lib COMPONENT bin
  INCLUDES DESTINATION my_project/include
)
install(FILES lib_stuff.hpp lib_stuff_2.hpp
        DESTINATION my_project/include COMPONENT dev)

# and export stuff so that other project can use the exported targets
without find modules...
install(EXPORT my-config
    DESTINATION cmake COMPONENT dev
    NAMESPACE my_project::
  )
#--------------------

Not something to really write home about but it works on Linux and Windows
and AIX... Including the different IDEs integration part...
Things can get messier when you require calling external code generator
tools or something like that. It also gets longer for calling tests - one
for each loop with test names and one command to add the test... So not
really complicated. Or a few lines for packaging - also not really rocket
science.

Daliel Pfeifer held a great talk on that:
https://www.youtube.com/watch?v=bsXLMQ6WgIk

And then things get somewhat more complicated when you have to directly
interact with the compiler for a certain platform:

#-----------
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  if(CMAKE_BUILD_TYPE MATCHES DEBUG)
    set_target_properties(my_fancy_lib PROPERTIES COMPILE_FLAGS "/MTd")
  else()
    set_target_properties(my_fancy_lib PROPERTIES COMPILE_FLAGS "/MT")
  endif()
endif()
#-----------

This could also be written with generator expressions if you don't like to
use variables (which is a bit more hieroglyphic):

#-----------
set_target_properties(my_fancy_lib PROPERTIES COMPILE_FLAGS
    "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:DEBUG>>:/MTd>"
    "$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<CONFIG:RELEASE>>:/MT>"
)
#-----------

So the syntax is not really terrible compared to Faber's (at least for me)
and gives you both abstract and low level control and cross platform
support without jumping through hoops. This is what you are competing
against from my point of view.

Regards,
Domen


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk