# correct usage of cmake\_parse\_arguments: specialization of find\_package use-case

**URL:** <https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376>\
**Category:** Code\
**Created:** [December 8, 2025, 1:40pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376 "2025-12-08T13:40:46Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [December 8, 2025, 1:40pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/1 "2025-12-08T13:40:46Z")

</div>

Hi,

I’m experimenting with a macro `find_package` in order to add some custom logic to `find_package`.

I’d like to use `cmake_parse_arguments` in order to filter the arguments. My first try is like this to get only the components if any:

```cmake
macro(find_package)

    set(multiValueArgs COMPONENTS)
    cmake_parse_arguments(arg_my_find_package "${multiValueArgs}" ${ARGN})
    ...

```

But a call such as `find_package(pack COMPONENTS comp)` gives:

> (cmake\_parse\_arguments):  
> keyword defined more than once: COMPONENTS

And the variable `${arg_my_find_package_COMPONENTS}` is empty.

NB with `find_package(pack)` `${arg_my_find_package_COMPONENTS}` is set to `FALSE` as expected.

How can I have the expected behavior (getting the COMPONENTS and only them)?

Regards,  
A.

---

<div class="post-metadata">

**Author:** ![AnthonyD973](https://discourse.cmake.org/user_avatar/discourse.cmake.org/anthonyd973/32/3130_2.png) [@AnthonyD973](https://discourse.cmake.org/u/AnthonyD973)\
**Post date:** [December 8, 2025, 7:58pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/2 "2025-12-08T19:58:13Z")

</div>

> [@adaldev](#):
>
> `cmake_parse_arguments(arg_my_find_package "${multiValueArgs}" ${ARGN})`

You’re actually supposed to pass all arguments to `cmake_parse_arguments`; it can’t guess what argument type you intended:

```cmake
    set(options)
    set(oneValueArgs)
    set(multiValueArgs COMPONENTS)
    cmake_parse_arguments(arg_my_find_package
        "${options}" "${oneValueArgs}" "${multiValueArgs}"
        ${ARGN}
    )

```

For that matter it’s safer to use the `PARSE_ARGV` form of `cmake_parse_arguements`; this avoids issues when certain characters such as semicolons are present in the arguments:

```cmake
    set(options)
    set(oneValueArgs)
    set(multiValueArgs COMPONENTS)
    cmake_parse_arguments(PARSE_ARGV 0 arg_my_find_package
        "${options}" "${oneValueArgs}" "${multiValueArgs}")

```

For more info, see the docs: [https://cmake.org/cmake/help/latest/command/cmake\_parse\_arguments.html](https://cmake.org/cmake/help/latest/command/cmake_parse_arguments.html)

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [December 8, 2025, 8:15pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/3 "2025-12-08T20:15:29Z")

</div>

> [@adaldev](#):
>
> I’m experimenting with a macro `find_package` in order to add some custom logic to `find_package`.

Do not override built-in commands. I write a blog article discussing this very topic, and another related follow-up article discussing forwarding of command arguments:

- [Do Not Redefine CMake Commands](https://crascit.com/2018/09/14/do-not-redefine-cmake-commands/)
- [Forwarding Command Arguments In CMake](https://crascit.com/2019/01/29/forwarding-command-arguments-in-cmake/)

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [December 9, 2025, 8:29am UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/4 "2025-12-09T08:29:04Z")

</div>

Dear Mr Scott,

Thanks for the valuable links.

Regarding first the argument forwarding I’ll have to experiments. I don’t quite understand the official documentation:

> Added in version 3.7: The `PARSE_ARGV` signature is only for use in a [`function()`](https://cmake.org/cmake/help/latest/command/function.html#command:function) body. In this case, the arguments that are parsed come from the `ARGV#` variables of the calling function. The parsing starts with the `<N>`-th argument, where `<N>` is an unsigned integer. This allows for the values to have special characters like `;` in them.

In what way does it help for arguments containing `;`?

Besides, your post explains the dangers of argument forwarding but I don’t get if it gives a solution. Isn’t there, for instance a reciprocal of `cmake_parse_arguments`?

Regarding specializing `find_package` I get your point. But I really need this specialization in order to manage ill-packaged libraries (such as OpenCV) or customer-side complex configurations (typically, I’m compiling with different ABI on the same compiler and have to chose the actual path to the dependency according to the project configuration).

At short term, I think I will implement an option to import my specialization or not, document it, mentioning the risks you pinpointed and issuing a CMake warning when used.

Nevertheless, wouldn’t it be useful to have then a documented `native_find_package` function that implements the standard behavior (and whose redefinition would indeed be “undefined behavior”), that can be used to do such specialization without relying on the underscore trick? It seems really straightforward to implement. Is it worth posting a feature request?

Regards  
A.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [December 9, 2025, 8:29am UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/5 "2025-12-09T08:29:51Z")

</div>

Thanks,

I didn’t get it straight from the doc first that all the arguments were mandatory.

Regards  
A.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [December 9, 2025, 8:58pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/6 "2025-12-09T20:58:44Z")

</div>

> [@adaldev](#):
>
> > Added in version 3.7: The `PARSE_ARGV` signature is only for use in a [`function()`](https://cmake.org/cmake/help/latest/command/function.html#command:function) body. In this case, the arguments that are parsed come from the `ARGV#` variables of the calling function. The parsing starts with the `<N>`-th argument, where `<N>` is an unsigned integer. This allows for the values to have special characters like `;` in them.
> 
> In what way does it help for arguments containing `;`?

It allows you to handle cases like this:

```cmake
cmake_minimum_required(VERSION 4.1)

function(some_command)
    cmake_parse_arguments(PARSE_ARGV 0 arg "" "" "THINGS")

    foreach(arg IN LISTS arg_THINGS)
        message(STATUS "arg: ${arg}")
    endforeach()
endfunction()

some_command(THINGS aaa "bbb;ccc" ddd)

```

The output from the above would be:

```auto
-- arg: aaa
-- arg: bbb;ccc
-- arg: ddd

```

Note how the second value after the `THINGS` keyword contains a semicolon. The quotes around `bbb;ccc` means the caller wants to treat that as a single argument. The `PARSE_ARGV` form of `cmake_parse_arguments()` preserves that. If you used the older, non-`PARSE_ARGV` form that uses `${ARGN}` to provide the arguments to `cmake_parse_arguments()`, the effect of the quotes is lost, resulting in `bbb` and `ccc` being seen as distinct, separate arguments.

> [@adaldev](#):
>
> Besides, your post explains the dangers of argument forwarding but I don’t get if it gives a solution. Isn’t there, for instance a reciprocal of `cmake_parse_arguments`?

I don’t understand your question, sorry. What do you mean by a "reciprocal of `cmake_parse_arguments`?

> [@adaldev](#):
>
> Regarding specializing `find_package` I get your point. But I really need this specialization in order to manage ill-packaged libraries (such as OpenCV) or customer-side complex configurations

The [dependency providers](https://cmake.org/cmake/help/latest/guide/using-dependencies/index.html#dependency-providers) feature is the supported way for you to deal with that. Dependency providers allow you to intercept `find_package()` calls and handle them in whatever way you want. Note though that a dependency provider is meant to be the choice of the user, not the project.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [December 10, 2025, 1:35pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/7 "2025-12-10T13:35:35Z")

</div>

Great! I wasn’t aware of the dependency providers feature. Thank you for having shared your helpful insights and advice. I’m certain it will prove very useful.

Thanks also for the details regarding argument parsing.

Regards,  
A.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [December 12, 2025, 5:28pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/8 "2025-12-12T17:28:18Z")

</div>

From CMake documentation:

> Only one provider can be set at any point in time. If a provider is already set when `cmake_language(SET_DEPENDENCY_PROVIDER)` is called, the new provider replaces the previously set one. The specified `<command>` must already exist when `cmake_language(SET_DEPENDENCY_PROVIDER)` is called. As a special case, providing an empty string for the `<command>` and no `<methods>` will discard any previously set provider.
> 
> The dependency provider can only be set while processing one of the files specified by the [`CMAKE_PROJECT_TOP_LEVEL_INCLUDES`](https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.html#variable:CMAKE_PROJECT_TOP_LEVEL_INCLUDES) variable. Thus, dependency providers can only be set as part of the first call to [`project()`](https://cmake.org/cmake/help/latest/command/project.html#command:project). Calling `cmake_language(SET_DEPENDENCY_PROVIDER)` outside of that context will result in an error.

I can’t see how you can set a new provider if `cmake_language` can be called only once. Could you provide an example?

regards  
A.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [December 12, 2025, 7:41pm UTC](https://discourse.cmake.org/t/correct-usage-of-cmake-parse-arguments-specialization-of-find-package-use-case/15376/9 "2025-12-12T19:41:45Z")

</div>

You _can_ call `cmake_language(SET_DEPENDENCY_PROVIDER)` more than once, but each call is a complete replacement of any earlier such call. The key restriction is that the only place you are allowed to call `cmake_language(SET_DEPENDENCY_PROVIDER)` is from one of the files listed in `CMAKE_PROJECT_TOP_LEVEL_INCLUDES`. It’s fine, for example, if there are two files listed in that variable, and each one calls `cmake_language(SET_DEPENDENCY_PROVIDER)` to set a provider. The result of the first call will be discarded and the second call will be the one that takes effect.

Projects shouldn’t normally set the dependency provider. A CMake preset might set one, but the user is still free to override or not use that. This is all by design, so that users are always in control and projects cannot lock them out of having a choice (whether deliberate or by accident).
