Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMakeList.txt Changes Required for Boost Challenges #330

Closed
stungeye opened this issue Jan 4, 2020 · 10 comments
Closed

CMakeList.txt Changes Required for Boost Challenges #330

stungeye opened this issue Jan 4, 2020 · 10 comments

Comments

@stungeye
Copy link

stungeye commented Jan 4, 2020

Hi all. I know there some closed issues about Boost, specifically its use in the Gigasecond and Meetup questions. For example: #311

I also see that adding instructions for installing Boost was considered but it was thought that students could Google the install instructions relevant to their setup.

That said, I just had a heck of a time getting Boost installed with Visual Studios 2019 in order to attempt the Gigasecond question. It turned out that I had to add/change three lines in the CMakeLists.txt file, but finding those three lines took a long time.

After I installed the Boost Binaries for Windows I had to hint in CMakeLists.txt the location of my Boost binaries, and then change the version number for find_package:

set(BOOST_ROOT "C:/local/boost_1_72_0")
find_package(Boost 1.72 REQUIRED COMPONENTS date_time)

Then in order for the boost namespace and the ptime symbol to resolve in my source code I had to add an INCLUDE_DIRECTORIES to CMakeLists.txt:

# Added below the above find_package statement.
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})

Do y'all think the INCLUDE_DIRECTORIES statement should be added to the provided CMakeLists.txt file with a note about the BOOST_ROOT in the readme?

Knowing these three things up front would have saved me a few hours of Googling and experimentation.

cc: @patricksjackson @KevinWMatthews

@KevinWMatthews
Copy link
Contributor

Hey @stungeye,

Thanks for posting - it's good to get some recent, real-world feedback. And yes, configuring Boost always seems to be troublesome.

Big picture, to make sure I grok you: configuring Boost for the Gigasecond and Meetup exercises is difficult, but we could help out by adding a few hints to our CMakeLists.txt. I agree :)

A few thoughts on your problem and solution:

set(BOOST_ROOT "C:/local/boost_1_72_0")

I can see why setting BOOST_ROOT would help out. Another alternative may be to extend the search path for find_package() by appending to the list variable CMAKE_PREFIX_PATH.

find_package(Boost 1.72 REQUIRED COMPONENTS date_time)

Huh, that's odd. I thought that the version was the minimum allowed unless EXACT is specified; double-check in the FindBoost docs. You're seeing failure if you set BOOST_ROOT appropriately but set the version to 1.58?

INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})

Wait, something doesn't make sense yet.... CMake's find_package is designed to prevent you from having to do this. I wonder if something else in the setup process is going awry?

Some context, in the hope that I'll be corrected if I misunderstand something. In the ideal case, find_package will to search the system for a library and, if found, package up all the library's usage requirements into an "alias target" (those have :: in the name). Users can simply link their executable against such an alias target, and that should pull in all of the library requirements automagically.

Theoretically, CMake's FindBoost module works like this. Calling find_package(BOOST) should invoke FindBoost, which captures both library requirements (Boost_LIBRARY_DIRS, Boost_LIBRARIES, etc) and header requirements (Boost_INCLUDE_DIRS) and packages them up into a set of alias targets such as Boost::date_time. From there, all that is required is to link the executable with this alias target (we do that here, for example).

Theoretically ;) Apparently something in the chain isn't working, though I'm unsure what it is.

Is it possible to set the CMake search path (CMAKE_PREFIX_PATH) natively within Visual Studio? That might prevent you from having to edit CMakeLists.txt.

It's also possible that Visual Studio itself is having issues; for example, see here.

Thoughts?

@stungeye
Copy link
Author

stungeye commented Jan 5, 2020

Hi @KevinWMatthews. Thanks for the super quick and detailed response. Before I continue let me say that I'm enjoying the C++ track on Exercism immensely. I coded in C++ early in my career but spent the past 15 years in the web world with dynamically typed languages. Exercism has been crucial get getting me back up to speed with modern C++. The tests all just work and although there only seems to be one moderator commenting on my solutions the feedback they are providing is amazing.

Okay. Back to the issue at hand. You are correct with your assessment of the situation:

  1. The call to find_package works correctly if the version is left at 1.58.
  2. The addition of INCLUDE_DIRECTORIES also isn't required.

Visual Studio was making it hard for me to see the effect of my changes to CMakeLists.txt by caching things behind the scenes. In some cases deleting the CMake cache wasn't enough of a clean slate and restarting Visual Studio was required.

So, this leaves me with only one required change:

set(BOOST_ROOT "C:/local/boost_1_72_0")

Which hilariously was the first thing that I tried, but due to me not understanding CMake and the required Visual Studio restart described above, it didn't initially solve my problem.

This set can be avoided. After further investigation it turns out that you can hint to find_package the location of Boost in Visual Studio by overriding the CMake variable Boost_INCLUDE_DIR from the Project => "CMake Setttings" menu. When I first go to this menu this include dir is set to Boost_INCLUDE_DIR-NOTFOUND:

cmake_settings_boost

But it can be manually set to the correct path:

cmake_settings_boost_next

You then have to persist this change by saving the settings, and in the process creating a CMakeSettings.json file. See mine here, renamed to a .json.txt: CMakeSettings.json.txt

After saving that setting I can compile and run the gigasecond program with an unmodified CMakeLists.txt, but I still need to restart Visual Studio once in order for the Boost namespace and the ptime symbol to properly resolve when editing files. Without the restart ptime is shown in red as an undefined identifier. The requirement for a restart is no doubt an issue with Visual Studio.

Do you think it would be worth mentioning the Boost_INCLUDE_DIR and Visual Studio's "CMake Setttings" menu in the readme for this exercise for future Windows students?

@KevinWMatthews
Copy link
Contributor

Hi @stungeye,

Thanks for the update - things make a bit more sense now. Thanks also for doing some detective work - I don't have Visual Studio myself, sadly, so I appreciate you experimenting so much.

Does Visual Studio provide a way to set CMAKE_PREFIX_PATH? This should set the search path for find_package() before it runs. Setting Boost_INCLUDE_DIR works but it seems more like triage after the fact; find_package(BOOST) has to run and fail before the variable exists, right?

CMAKE_PREFIX_PATH just might be available if you check the "Show advanced variables" checkbox, but I'm pretty sure that you have to create the variable manually. From the CMake docs:

By default this is empty. It is intended to be set by the project.

If this works, it seems to be the most straightforward and general solution.

Do you think it would be worth mentioning the Boost_INCLUDE_DIR and Visual Studio's "CMake Setttings" menu in the readme for this exercise for future Windows students?

Yes, but.... It's always complicated. Two thoughts thus far:

  • IDE-specific configuration is a moving target
  • Boost_INCLUDE_DIR might not be the "best" setting to modify (TBD)

On the first point, we try to balance how specific our instructions are because IDE's change over time. Ideally, the IDE itself will provide appropriate docs. In practice, your experience shows that we have room for improvement.

On the second, it's preferable to set CMAKE_PREFIX_PATH if it actually works. This could fix the problem before it happens, and this technique applies to linking any external library (and to CMake in general, not just Visual Studio).

@KevinWMatthews
Copy link
Contributor

Glad to hear that you're having a good experience with Exercism! I do know that the mentors (all volunteers?) have a pretty big workload cut out for them, so I wouldn't be surprised if they tend to follow students through the track.

@stungeye
Copy link
Author

stungeye commented Jan 6, 2020

I am able to set CMAKE_PREFIX_PATH to my Boost folder by manually editing the CMakeSettings.json using the "Edit JSON" link found in the Visual Studio "Project" => "CMake Setttings" menu item.

My CMakeSettings.json file looks like this now (extension changed to .json.txt for GitHub upload):
CMakeSettings.json.txt

One other thing I didn't mention above, but that should be noted in case future Visual Studio users see this thread, is that I had to download Boost from boost.teeks99.com rather than from the official Boost website in order to get the pre-compiled binaries for Visual Studio.

Lastly, debugging all this was made much easier by adding the following to the CMakeLists.txt above the find_package statement:

set (Boost_DEBUG ON)

This setting adds a bunch of helpful details to the CMake cache generation output.

After all this I wonder if the gigasecond and meetup exercises should be refactored to use std::chrono instead of Boost's data_time? (I see this has been discussed before in #159 / #224 and that calendar additions are coming to std::chrono in C++20.)

@arcuru
Copy link
Contributor

arcuru commented Jan 8, 2020

std::chrono should absolutely replace Boost here once we are able to use it with our minimum supported versions. I think that we need the features coming to std::chrono in C++20 though, so it will be on the order of several years before we can switch.

Our current min version doesn't yet support C++17.

@stungeye
Copy link
Author

stungeye commented Jan 9, 2020

Thanks for all your feedback here @patricksjackson. I have a better understanding of CMake and Visual Studio now. Much appreciated. I'm going to be creating and teaching some college-level C++ courses soon and will be including the Exercism CPP track in the mix.

Shall we close this issue now?

@KevinWMatthews
Copy link
Contributor

I'm leaning toward leaving it open and adding a small note to either the README or the comment at the start of the tests. Maybe extend this comment with something like:

If Boost is installed to a custom directory, you may need to set CMAKE_PREFIX_PATH to point to this location.

Thoughts on the verbiage?

@stungeye
Copy link
Author

stungeye commented Jan 9, 2020

Sounds good to me! I'll likely make a short blog post and/or youtube tutorial on using pre-built Boost binaries with Visual Studio to capture what I've learned.

@arcuru
Copy link
Contributor

arcuru commented Sep 11, 2021

Closing this. We now have an online test runner that will work for people who have issues installing it locally.

@arcuru arcuru closed this as completed Sep 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants