Skip to content

Automatically find externals#15158

Merged
tgamblin merged 55 commits intospack:developfrom
scheibelp:features/find-externals
May 6, 2020
Merged

Automatically find externals#15158
tgamblin merged 55 commits intospack:developfrom
scheibelp:features/find-externals

Conversation

@scheibelp
Copy link
Copy Markdown
Member

@scheibelp scheibelp commented Feb 21, 2020

Add a spack external find command which searches through $PATH and tries to create a packages.yaml of external packages. This focuses on finding build dependencies (currently only cmake).

To make a package discoverable with spack external find the package must define an .executables class attribute: a collection of executable names. If Spack finds these executables, it will create a packages config entry for them. If the package also defines .determine_spec_details, the executables will be passed to that function, which can generate a more-specific packages.yaml entry (including version, variants or whatever else the user decides to determine).

This currently outputs the relevant yaml configuration to the terminal and doesn't have an option to generate a packages.yaml file.

Closes #2507
Fixes #13198
Fixes #2116

@scheibelp scheibelp added the WIP label Feb 21, 2020
@scheibelp scheibelp requested a review from alalazo March 10, 2020 17:23
@alalazo
Copy link
Copy Markdown
Member

alalazo commented Mar 11, 2020

I think the core proposal in #1795 might be of interest for a broader discussion. The basic idea is that a package that is detected as an external can be symlinked into a Spack owned directory. This would ensure that:

  1. We don't introduce spurious dependencies by adding system folders as prefixes
  2. We have a correct modelling of what needs to be detected for any external package that supports the detection API (if a critical component is missing, recipes are more likely to fail if we are out of system paths)

@scheibelp
Copy link
Copy Markdown
Member Author

[This would ensure that] We have a correct modelling of what needs to be detected for any external package that supports the detection API (if a critical component is missing, recipes are more likely to fail if we are out of system paths)

I would like to give users the option to specify a subset of files (e.g. if a cmake exe is available on the system, I assume it is likely to work). Allowing users to specify more required files could be useful.

[This would ensure that] We don't introduce spurious dependencies by adding system folders as prefixes

I think this can be treated as a separate issue: we already allow users to add external packages which are located in system folders (and in that case they enter the system folder as the prefix). Spack's logic already handles this case so it should be the same for automatically adding externals with system prefixes.

The basic idea is that a package that is detected as an external can be symlinked into a Spack owned directory.

Overall I'm not sure of the benefit of this (vs. detecting and using system prefixes). I admit it sounds good to me, but I think we already need to handle the existence of system prefixes, so I'm not sure if separating the files into a different prefix is beneficial.

Copy link
Copy Markdown
Member

@alalazo alalazo left a comment

Choose a reason for hiding this comment

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

I left a few comments, let me know what you think.

@scheibelp

This comment has been minimized.

@scheibelp

This comment has been minimized.

@tgamblin tgamblin self-requested a review April 21, 2020 03:28
… relevant exes found in that prefix; it can return multiple specs from a single call (although generally the package config can't distinguish the specs). determine_spec_details can return a single spec if the user doesn't want to implement the logic to detect multiple versions in a single prefix
@scheibelp
Copy link
Copy Markdown
Member Author

@tgamblin @alalazo this is ready for another look

@scheibelp
Copy link
Copy Markdown
Member Author

scheibelp commented Apr 29, 2020

I should add a section on things that are not yet addressed but I presume they could be handled with a later PR:

All other concerns are addressed at this point.

@scheibelp scheibelp removed the WIP label Apr 30, 2020
…ndidate exe was not an instance of the package was triggering incorrectly. remove confusing and incorrect use of for/else python syntax
Copy link
Copy Markdown
Member

@alalazo alalazo left a comment

Choose a reason for hiding this comment

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

LGTM. I think all the other points mentioned in the discussion can be implemented in subsequent PRs. I left a couple of minor comments.

groups = defaultdict(set)
for p in paths:
groups[os.path.dirname(p)].add(p)
return groups.items()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we can return:

result = sorted([(prefix, sorted(s)) for prefix, s in groups.items()])

to solve the TODO below

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That would do it, although the TODO I have in the code mentions that it might be better to do it based on order of prefixes in PATH (so the results are repeatable and follow an intuitive rule).

match = re.search(r'cmake.*version\s+(\S+)', output)
if match:
version_str = match.group(1)
return Spec('cmake@{0}'.format(version_str))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we can just:

Suggested change
return Spec('cmake@{0}'.format(version_str))
return 'cmake@{0}'.format(version_str)

and move the logic that parses the string into Specs in the command, as you suggested in a comment above.

Copy link
Copy Markdown
Member

@tgamblin tgamblin left a comment

Choose a reason for hiding this comment

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

@scheibelp: this LGTM. Can you please add documentation before we merge it?

@scheibelp
Copy link
Copy Markdown
Member Author

Can you please add documentation before we merge it?

@tgamblin I have added documentation in 8af0872

Specific limitations include:

* A package must define ``executables`` and ``determine_spec_details``
for Spack to locate instances of that package.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This needs further explanation in the packaging guide -- what's the signature for the method, what should executables contain, and how is finding done based on those two things? Can you add that?

* A package must define ``executables`` and ``determine_spec_details``
for Spack to locate instances of that package.
* This is currently intended to find build dependencies rather than
library packages.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably should say why -- because it can only find executable programs right now.

can help locate all external entries).
* Currently this logic is focused on examining ``PATH`` and does not
search through modules (although it should find the package if a
module is loaded for it).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is related to the second bullet above and should be combined.

Copy link
Copy Markdown
Member

@tgamblin tgamblin left a comment

Choose a reason for hiding this comment

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

@scheibelp: can you add the documentation above in a follow-on PR?

@tgamblin tgamblin merged commit b030a81 into spack:develop May 6, 2020
scheibelp added a commit to scheibelp/spack that referenced this pull request May 6, 2020
@adamjstewart
Copy link
Copy Markdown
Member

It seems like spack external find can only find the first instance of an external package? What if you have multiple copies of a package like Python installed and you want to pick up both Python 2 and 3?

@adamjstewart
Copy link
Copy Markdown
Member

Also, the prefix Spack chooses is non-deterministic. Sometimes I get my Spack-installed Python 3, sometimes I get my system Python 2, and sometimes I get spack-python.

P.S. I'm working on adding spack external find python support

@adamjstewart
Copy link
Copy Markdown
Member

Ah, now that I have it working it seems to run this function for each unique prefix. What about when both Python 2 and 3 are installed to the same directory?

@alalazo
Copy link
Copy Markdown
Member

alalazo commented May 16, 2020

What about when both Python 2 and 3 are installed to the same directory?

@adamjstewart You might want to look at #16526 which builds on this PR and implements detection logic for gcc.

@adamjstewart
Copy link
Copy Markdown
Member

Also, this PR suffers from the same issue as #12313, it reorganizes my packages.yaml, including existing entries.

@adamjstewart
Copy link
Copy Markdown
Member

Btw, I got bored, so I'm going to add spack external find support for common build dependencies, like:

$ egrep -ho 'depends_on\(.(\w+).*type=.build' */package.py | cut -c 13- | egrep -o '^[A-Za-z0-9-]+' | sort | uniq -c | sort -n
...
  38 gmake
  41 flex
  53 bison
  54 py-cython
  61 python
  79 xproto
 155 m4
 181 util-macros
 187 automake
 190 autoconf
 195 libtool
 286 cmake
 347 pkgconfig
 719 py-setuptools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add standard variant 'find-on-system' to many of the low-level ubiquitous packages to avoid Spack trying to build them Find System-Provided Packages

4 participants