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

Add UI for specifying CMake tools and generators' locations #1067

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

DangMinhTam382
Copy link
Contributor

Add UI for specifying CMake tools and generators locations

Adding UI into CMake Preference page that allow user to specify the
location of the CMake tool and the location of CMake generators.
Added CMakeBuildEnvironmentSupplier.class for ICBuildConfiguration

Addresses Issue: CDT CMake Improvements #1000, IDE-82683-REQ-004 and
IDE-82683-REQ-005

Copy link

github-actions bot commented Jan 29, 2025

Test Results

   603 files     603 suites   13m 26s ⏱️
10 228 tests 10 204 ✅ 24 💤 0 ❌
10 266 runs  10 242 ✅ 24 💤 0 ❌

Results for commit 5aa5354.

♻️ This comment has been updated with latest results.

@betamaxbandit

This comment was marked as outdated.

@betamaxbandit

This comment was marked as outdated.

@jonahgraham jonahgraham added this to the 12.0.0 M3 milestone Feb 2, 2025
Copy link
Member

@jonahgraham jonahgraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this change. Please have a look at my comments and don't hesitate to reach out to me or @betamaxbandit if you need any clarification.

@@ -225,6 +227,10 @@ IEnvironmentContextInfo getDefaultContextInfo(Object level) {
* or null if the the given level is not supported
*/
public IEnvironmentContextInfo getContextInfo(Object level) {
if (level instanceof ICBuildConfiguration || level instanceof IBuildConfiguration buildConfiguration
&& buildConfiguration.getAdapter(ICBuildConfiguration.class) != null) {
return new CMakeEnvironmentContextInfo(getDefaultContextInfo(level));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what this code does a bit please as I don't understand full effect of this, but I do find it unexpected that we do getAdapter for ICBuildConfiguration, but then don't pass the ICBuildConfiguration to getDefaultContextInfo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when I test using a default CMake project, the level here is an instance of IBuildConfiguration.
When getDefaultContextInfo(IBuildConfiguration) is called, the return context info would contain 3 suppliers as:
suppliers = new ICoreEnvironmentVariableSupplier[] { EnvironmentVariableManager.fBuildConfigSupplier, EnvironmentVariableManager.fToolChainSupplier, EnvironmentVariableManager.fUserSupplier

But, if I call getDefaultContextInfo(ICBuildConfiguration) here, the supplier would only be
suppliers = new ICoreEnvironmentVariableSupplier[] { EnvironmentVariableManager.fUserSupplier, EnvironmentVariableManager.fEclipseSupplier

I'm not so certain about the impact on this one, so level is use here to avoid getting the false DefaultEnvironmentContextInfo

Here is the code block that I mentioned above: cdt/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/envvar/DefaultEnvironmentContextInfo.java

/*
* answers the list of suppliers that should be used for the given context
*/
protected ICoreEnvironmentVariableSupplier[] getSuppliers(Object context) {
ICoreEnvironmentVariableSupplier suppliers[];
if (context instanceof ICConfigurationDescription)
	suppliers = new ICoreEnvironmentVariableSupplier[] { EnvironmentVariableManager.fUserSupplier,
			EnvironmentVariableManager.fExternalSupplier };
else if (context instanceof IBuildConfiguration)
	suppliers = new ICoreEnvironmentVariableSupplier[] { EnvironmentVariableManager.fBuildConfigSupplier,
			EnvironmentVariableManager.fToolChainSupplier, EnvironmentVariableManager.fUserSupplier };
else
	suppliers = new ICoreEnvironmentVariableSupplier[] { EnvironmentVariableManager.fUserSupplier,
			EnvironmentVariableManager.fEclipseSupplier };
return suppliers;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @DangMinhTam382 ,
thanks for the explanation, but TBH I don't understand exactly what is required here.
I think @Kummallinen had a specific requirement here.

@jonahgraham

This comment was marked as resolved.

@@ -225,6 +227,10 @@ IEnvironmentContextInfo getDefaultContextInfo(Object level) {
* or null if the the given level is not supported
*/
public IEnvironmentContextInfo getContextInfo(Object level) {
if (level instanceof ICBuildConfiguration || level instanceof IBuildConfiguration buildConfiguration
&& buildConfiguration.getAdapter(ICBuildConfiguration.class) != null) {
return new CMakeEnvironmentContextInfo(getDefaultContextInfo(level));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @DangMinhTam382 ,
thanks for the explanation, but TBH I don't understand exactly what is required here.
I think @Kummallinen had a specific requirement here.

@betamaxbandit

This comment was marked as resolved.

@jonahgraham

This comment was marked as resolved.

@DangMinhTam382 DangMinhTam382 force-pushed the IDE_82683_REQ_004_005 branch 2 times, most recently from ce6f147 to 4bffb8d Compare February 12, 2025 08:17
@betamaxbandit

This comment was marked as resolved.

@jonahgraham

This comment was marked as resolved.

@DangMinhTam382

This comment was marked as resolved.

@DangMinhTam382 DangMinhTam382 force-pushed the IDE_82683_REQ_004_005 branch 2 times, most recently from 072517e to 05f5471 Compare February 13, 2025 10:43
betamaxbandit

This comment was marked as resolved.

Copy link
Member

@jonahgraham jonahgraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DangMinhTam382 Sorry for how many individual comments there are - most are trivial to fix and some of them are minor. But a handful of them are blocking. Please let me know if you have any follow-up questions.

import org.osgi.service.prefs.Preferences;

/**
* Test for IDE_82683_REQ_004_005

This comment was marked as resolved.

generatorLocationTextBox = new Text(locationComp, SWT.BORDER);
generatorLocationTextBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
generatorLocationTextBox.setEditable(false);
generatorLocationTextBox.setText(String.join(VALUE_DELIMITER, generatorLocations));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This text box can grow really wide as it tries to fit the whole string here. So if you have long or many paths you end up with very wide locationComp and end up with a horizontal scroll bar on the preference page

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out! I do notice it when reopen dialog after long locations added.

I added this block right here to make locationComp has a widthHint so it won't be too wide.
https://github.com/DangMinhTam382/cdt/blob/45be12bb62a98052d2728a682f848def892203e9/cmake/org.eclipse.cdt.cmake.ui/src/org/eclipse/cdt/cmake/ui/internal/CMakePreferencePage.java#L200-L203

@jonahgraham
Copy link
Member

@betamaxbandit / @DangMinhTam382 / @Kummallinen

I have spent a bunch of time trying to understand what is going on here, and I have left a long review. However now that I have completed it I feel many parts of the review are at too low a level and miss out on the higher level objectives #1000 IDE-82683-REQ-004 and IDE-82683-REQ-005 aim to set out. The quoted items are from the PDF in #1000 on those requirements, with some bolding by me for emphasis.

Here are some issues that must resolved:

PATH environment of processes that are launched to execute CMake build and debug operations.

The new CMake variable supplier is applying itself to non-CMake projects. e.g. if I build a Makefile core build project the settings in the new CMake preference page affect the PATH used for it.

Quick Fix action a user has launched.

I am unsure how this requirement is being implemented.

The precedence of the location specified in "CMake location" is important and should be added to the PATH environment variable, so it is in front of other system environment locations, but behind any locations added by an ISV.

The new CMake variable supplier is added to the available suppliers with CMakeEnvironmentContextInfo.getSuppliers() - this places the new CMake supplier at the end of the existing suppliers. This means if any other supplier also has a PREPEND for PATH, those other suppliers put their PATH entries in front of the CMake one. In particular, the ToolChainEnvironmentSupplier has higher precedence and it places the path to the toolchain in front of the paths added for CMake.

A particular use case that does not work, although it is implied to work by the new GUI, is if:

  • I am using toolchain /usr/bin/gcc
  • I have cmake installed in /usr/bin/cmake - but it is an older version of cmake than I want
  • I have cmake installed in /opt/cmake/cmake-3.29.2-linux-x86_64/bin/cmake and this is the version I want
  • Then in the new GUI I point to /opt/cmake/cmake-3.29.2-linux-x86_64/bin

If I build, it will still use /usr/bin/cmake.

Note that this isn't actually a regression. The same "wrong" cmake is used when I don't have this PR. But I think that this new GUI/preference should solve this bug.

PATH environment of processes that are launched to execute CMake build and debug operations.

When debugging, the PATH in the inferior is broken with null string replacing part of the PATH. This is not exactly a regression either. To reproduce try creating a CMake project and adding std::cout << getenv("PATH") << std::endl;. When I Run the expected output is shown, when I debug I get CMake + tool path, followed by :null

@betamaxbandit
Copy link
Contributor

Thanks for details analysis @jonahgraham...

PATH environment of processes that are launched to execute CMake build and debug operations.

The new CMake variable supplier is applying itself to non-CMake projects. e.g. if I build a Makefile core build project the settings in the new CMake preference page affect the PATH used for it.

This pollution of the environment is a serious issue.
Minimally we need manual tests which exercise the Core Build projects (Autotools, Makefile, Meson) which prove the environment does not contain the added cmake environments. I guess these could include printing the build tool version during build.

@betamaxbandit
Copy link
Contributor

Quick Fix action a user has launched.

I am unsure how this requirement is being implemented.

When I spec'd this in IDE_82683_REQ_004 I did not elaborate. This item comes from requirement IDE_82683_REQ_003 which is not being implemented in the CDT12.0 timeframe, so the specification has not been developed. I assumed it could be "added" on later. I presume the cmake location values preference node (CMakeBuildEnvironmentSupplier.CMAKE_LOCATION) could be set by the quick fix action without needing to add API. Is this adequate?

@betamaxbandit
Copy link
Contributor

A particular use case that does not work, although it is implied to work by the new GUI, is if:

I am using toolchain /usr/bin/gcc
I have cmake installed in /usr/bin/cmake - but it is an older version of cmake than I want
I have cmake installed in /opt/cmake/cmake-3.29.2-linux-x86_64/bin/cmake and this is the version I want
Then in the new GUI I point to /opt/cmake/cmake-3.29.2-linux-x86_64/bin
If I build, it will still use /usr/bin/cmake.

Note that this isn't actually a regression. The same "wrong" cmake is used when I don't have this PR. But I think that this new GUI/preference should solve this bug.

Are the following locations on your PATH environment variable before you launch eclipse?
/usr/bin/cmake
/opt/cmake/cmake-3.29.2-linux-x86_64/bin/cmake

Surely if that is the case then both these paths constitute what I referred to in my spec as "system" paths. And surely eclipse can have no control over which is used; it's purely down to order. Have I understood correctly?

@jonahgraham
Copy link
Member

My PATH when launching eclipse looks like (simplified to highlight issue) /opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/arm-none-eabi/bin:/usr/bin. I also have two toolchains, /usr/bin/gcc and /opt/arm-none-eabi/bin/arm-none-eabi-gcc, and two cmakes the 3.29 version, and an older version in /usr/bin/cmake. This is to ensure my preferred cmake appears in the search order before the system installed versions.

In a terminal if I run:

  • cmake it uses /opt/cmake/cmake-3.29.2-linux-x86_64/bin/cmake.
  • gcc it uses /usr/bin/gcc
  • arm-none-eabi-gcc it uses /opt/arm-none-eabi/bin/arm-none-eabi-gcc

However (without this patch), when building a CMake project in the IDE, which cmake is used will depend on which toolchain I am using.

If I am using:

  • gcc, then the toolchain provider adds /usr/bin to the front of the PATH so my PATH becomes /usr/bin:/opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/arm-none-eabi/bin:/usr/bin - this leads to /usr/bin/cmake being used in error
  • arm-none-eabi-gcc then the toolchain provider adds /opt/arm-none-eabi/bin to the front of the PATH so my PATH becomes /opt/arm-none-eabi/bin:/opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/arm-none-eabi/bin:/usr/bin - this leads to cmake 3.29 being used as I desire

I expected this patch to solve the problem described in the last paragraph, which means that when I manually configure CMake location: that CMake build configuration would ensure that the CMake I selected in preferences is used. i.e. fulfilling requirement The precedence of the location [...]. However what happens if I am using:

  • gcc, then the toolchain provider adds /usr/bin to the front of the PATH, and CMake provider adds cmake after toolchain. PATH becomes /usr/bin:/opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/arm-none-eabi/bin:/usr/bin - this leads to /usr/bin/cmake being used in error
  • arm-none-eabi-gcc then the toolchain provider adds /opt/arm-none-eabi/bin to the front of the PATH, and CMake provider adds cmake after toolchain. PATH becomes /opt/arm-none-eabi/bin:/opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/cmake/cmake-3.29.2-linux-x86_64/bin:/opt/arm-none-eabi/bin:/usr/bin - this leads to cmake 3.29 being used as I desire

Therefore my conclusion is that this implementation does not solve the bug, and it make it even less clear to the user what is happening. My expectation as a user is if I choose CMake location: to a specific CMake (and I don't have any ISVs interfering) that that is the version of CMake that is actually used.

This same problem applies to the generators, i.e the wrong ninja + make can be picked up. The same problem also applies on Windows, depending how you setup your machine.

The workaround for the current HEAD of CDT is one of:

  • Specify in the c make build configuration "Build Settings" GUI the full path to the CMake executable.
  • Remove /usr/bin/cmake
  • Avoid using /usr/bin/gcc toolchain entirely

@DangMinhTam382
Copy link
Contributor Author

Thanks for the detailed analysis Mr. @jonahgraham ,
I will look into this again and try to resolve the issues.

However, I high doubt these issues could be resolved in time for the CDT 12.0.0 release.
So, I think this PR should be postponed.

@jonahgraham jonahgraham removed this from the 12.0.0 M3 milestone Feb 14, 2025
@jonahgraham
Copy link
Member

Thanks @DangMinhTam382 for letting me know. I have removed the milestone and I have set this to a Draft state until it is ready for more work. Let me know when you want me to review it again.

Adding UI into CMake Preference page that allow user to specify the
location of the CMake tool and the location of CMake generators.
Added Unit test

Addresses Issue: CDT CMake Improvements eclipse-cdt#1000, IDE-82683-REQ-004 and
IDE-82683-REQ-005
@DangMinhTam382 DangMinhTam382 force-pushed the IDE_82683_REQ_004_005 branch from 45be12b to 5aa5354 Compare March 5, 2025 11:11
Copy link
Member

@jonahgraham jonahgraham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have done a code review and marked as resolved all issues that are fully resolved. The higher level design issue is still outstanding and we should discuss that at the end of March/early April

ICdtVariableManager vm = CCorePlugin.getDefault().getCdtVariableManager();
return vm.resolveValue(value, null, CMakeBuildEnvironmentSupplier.EMPTY_STRING, null);
} catch (CdtVariableException e) {
Activator.log(e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty message can be solved by adding some additional context, such as:

Suggested change
Activator.log(e);
Activator.log(Activator.errorStatus("Some informative message here about failing to resolve the variable", e));

testButton.addListener(SWT.Selection, e -> {
try {
Process p = Runtime.getRuntime().exec(new String[] {
resolveVariableValue(cmakeLocation) + File.separatorChar + "cmake", "--version" }); //$NON-NLS-1$ //$NON-NLS-2$
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If resolveVariableValue returns null here I think this will mean that null/cmake will be the result.

String.format(CMakeBuildEnvironmentSupplier.LOCATION_NODE, index),
CMakeBuildEnvironmentSupplier.EMPTY_STRING));
}
generatorLocations = genlocs.toArray(new String[0]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use more recent Java way to avoid having to resize the array:

Suggested change
generatorLocations = genlocs.toArray(new String[0]);
generatorLocations = genlocs.toArray(String[]::new);

@DangMinhTam382
Copy link
Contributor Author

Thanks for the review, sir!

The higher level design issue is still outstanding and we should discuss that at the end of March/early April
Sure!
In the meantime, I will resolve small issues and clean up some code.

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

Successfully merging this pull request may close these issues.

3 participants