Skip to content

Conversation

@otegami
Copy link
Contributor

@otegami otegami commented Nov 27, 2025

GitHub:

By default, exclude Requires.private dependencies from cflags and libs output to match pkgconf's
behavior.
When the new static: true option is specified,
include Requires.private dependencies for static linking scenarios.

This change makes the default behavior consistent with pkgconf while still supporting static linking
use-cases through an explicit option.

GitHub:
- ruby-gnome#41 (comment)
- ruby-gnome#41 (comment)

By default, exclude `Requires.private` dependencies
from cflags and libs output to match pkgconf's
behavior.
When the new `static: true` option is specified,
include `Requires.private` dependencies for static
linking scenarios.

This change makes the default behavior consistent with
pkgconf while still supporting static linking
use-cases through an explicit option.

Co-Authored-By: kou <kou@clear-code.com>
@otegami otegami force-pushed the use-requires-private-only-for-static-linking branch from 2a3e40a to c59ea43 Compare November 27, 2025 07:59
@otegami otegami force-pushed the use-requires-private-only-for-static-linking branch from c59ea43 to 183cb7b Compare November 27, 2025 08:06
@otegami
Copy link
Contributor Author

otegami commented Nov 27, 2025

On Windows, some test failed because of cflags...

D:/rubyinstaller-head-x64/bin/ruby.exe test/run.rb
===============================================================================
Failure: test_cflags(PkgConfigTest)
D:/a/pkg-config/pkg-config/test/test-pkg-config.rb:203:in 'PkgConfigTest#assert_pkg_config'
D:/a/pkg-config/pkg-config/test/test-pkg-config.rb:38:in 'PkgConfigTest#test_cflags'
     35: 
     36:   def test_cflags
     37:     omit("Fragile on macOS") if RUBY_PLATFORM.include?("darwin")
  => 38:     assert_pkg_config("glib-2.0", ["--cflags"], @glib.cflags)
     39:   end
     40: 
     41:   def test_cflags_only_I
<"-ID:/rubyinstaller-head-x64/msys64/ucrt64/include/glib-2.0 -I/tmp/local/lib/glib-2.0/include -ID:/rubyinstaller-head-x64/msys64/ucrt64/include"> expected but was
<"-ID:/rubyinstaller-head-x64/msys64/ucrt64/include/glib-2.0 -I/tmp/local/lib/glib-2.0/include">

diff:
? -ID:/rubyinstaller-head-x64/msys64/ucrt64/include/glib-2.0 -I/tmp/local/lib/glib-2.0/include -ID:/rubyinstaller-head-x64/msys64/ucrt64/include
Error: <"-ID:/rubyinstaller-head-x64/msys64/ucrt64/include/glib-2.0 -I/tmp/local/lib/glib-2.0/include -ID:/rubyinstaller-head-x64/msys64/ucrt64/include"> expected but was
<"-ID:/rubyinstaller-head-x64/msys64/ucrt64/include/glib-2.0 -I/tmp/local/lib/glib-2.0/include">.

ref: https://github.com/otegami/pkg-config/actions/runs/19729356341/job/56526836780#step:9:24


The pkgconf's behavior might be different between RubyInstaller and MSYS2.

RubyInstaller (pkgconf 2.5.1)

Output includes Requires.private cflags.

pkgconf --cflags glib-2.0
-I.../include/glib-2.0 -I.../lib/glib-2.0/include -I.../include

MSYS2 (pkgconf 2.5.1)

Output does NOT include Requires.private cflags.

pkgconf --cflags glib-2.0
-I.../include/glib-2.0 -I.../lib/glib-2.0/include

@otegami
Copy link
Contributor Author

otegami commented Nov 27, 2025

The difference is caused by pkgconf's system include path filtering.

MSYS2 environment

In MSYS2, pkgconf recognizes '/ucrt64/include' as a system include path and excludes it by default.

Command Output
pkgconf --cflags libpcre2-8 (empty)
pkgconf --cflags --keep-system-cflags libpcre2-8 -I.../ucrt64/include
pkgconf --cflags glib-2.0 2 paths (without /include)
pkgconf --cflags --keep-system-cflags glib-2.0 3 paths (with /include)

ref: https://github.com/otegami/pkg-config/actions/runs/19730472975/job/56530192519#step:5:97

Difference between RubyInstaller and MSYS2

  • MSYS2: pkgconf excludes system paths (like /ucrt64/include) by default
  • RubyInstaller: pkgconf does NOT exclude system paths (behaves like --keep-system-cflags)

This is likely due to different pkgconf build configurations or environment settings between the two?

@kou
Copy link
Member

kou commented Nov 28, 2025

Could you show the results of pkgconf --dump-personality on RubyInstaller's MSYS2 and no-RubyInstaller MSYS2?

@otegami otegami marked this pull request as draft November 28, 2025 02:11
@otegami
Copy link
Contributor Author

otegami commented Nov 28, 2025

Could you show the results of pkgconf --dump-personality on RubyInstaller's MSYS2 and no-RubyInstaller MSYS2?

Sure, the result is the following.
I'm little bit confused now. I will sort of my thoughts too now on.

RubyInstaller's MSYS2

Run echo "=== pkgconf --version ==="
=== pkgconf --version ===
2.5.1

=== pkgconf --dump-personality ===
Triplet: default
DefaultSearchPaths: D:/rubyinstaller-head-x64/msys64/ucrt64/bin/../lib/pkgconfig D:/rubyinstaller-head-x64/msys64/ucrt64/bin/../share/pkgconfig 
SystemIncludePaths: /ucrt64/include 
SystemLibraryPaths: /ucrt64/lib 

no-RubyInstaller MSYS2

Run echo "=== pkgconf --version ==="
=== pkgconf --version ===
2.5.1

=== pkgconf --dump-personality ===
Triplet: default
DefaultSearchPaths: D:/a/_temp/msys64/ucrt64/bin/../lib/pkgconfig D:/a/_temp/msys64/ucrt64/bin/../share/pkgconfig 
SystemIncludePaths: /ucrt64/include 
SystemLibraryPaths: /ucrt64/lib 

@kou
Copy link
Member

kou commented Nov 28, 2025

Could you also share pkgconf --help on both environments?

@otegami
Copy link
Contributor Author

otegami commented Nov 28, 2025

Could you also share pkgconf --help on both environments?

Sure.

RubyInstaller MSYS2

pkgconf --helpのログ
=== pkgconf --help ===
usage: pkgconf [OPTIONS] [LIBRARIES]

basic options:

  --help                            this message
  --about                           print pkgconf version and license to stdout
  --version                         print supported pkg-config version to stdout
  --verbose                         print additional information
  --atleast-pkgconfig-version       check whether or not pkgconf is compatible
                                    with a specified pkg-config version
  --errors-to-stdout                print all errors on stdout instead of stderr
  --print-errors                    ensure all errors are printed
  --short-errors                    be less verbose about some errors
  --silence-errors                  explicitly be silent about errors
  --list-all                        list all known packages
  --list-package-names              list all known package names
  --simulate                        simulate walking the calculated dependency graph
  --no-cache                        do not cache already seen packages when
                                    walking the dependency graph
  --log-file=filename               write an audit log to a specified file
  --with-path=path                  adds a directory to the search path
  --define-prefix                   override the prefix variable with one that is guessed based on
                                    the location of the .pc file
  --dont-define-prefix              do not override the prefix variable under any circumstances
  --prefix-variable=varname         sets the name of the variable that pkgconf considers
                                    to be the package prefix
  --relocate=path                   relocates a path and exits (mostly for testsuite)
  --dont-relocate-paths             disables path relocation support

cross-compilation personality support:

  --personality=triplet|filename    sets the personality to 'triplet' or a file named 'filename'
  --dump-personality                dumps details concerning selected personality

checking specific pkg-config database entries:

  --atleast-version                 require a specific version of a module
  --exact-version                   require an exact version of a module
  --max-version                     require a maximum version of a module
  --exists                          check whether or not a module exists
  --uninstalled                     check whether or not an uninstalled module will be used
  --no-uninstalled                  never use uninstalled modules when satisfying dependencies
  --no-provides                     do not use 'provides' rules to resolve dependencies
  --maximum-traverse-depth          maximum allowed depth for dependency graph
  --static                          be more aggressive when computing dependency graph
                                    (for static linking)
  --shared                          use a simplified dependency graph (usually default)
  --pure                            optimize a static dependency graph as if it were a normal
                                    dependency graph
  --env-only                        look only for package entries in PKG_CONFIG_PATH
  --ignore-conflicts                ignore 'conflicts' rules in modules
  --validate                        validate specific .pc files for correctness

querying specific pkg-config database fields:

  --define-variable=varname=value   define variable 'varname' as 'value'
  --variable=varname                print specified variable entry to stdout
  --cflags                          print required CFLAGS to stdout
  --cflags-only-I                   print required include-dir CFLAGS to stdout
  --cflags-only-other               print required non-include-dir CFLAGS to stdout
  --libs                            print required linker flags to stdout
  --libs-only-L                     print required LDPATH linker flags to stdout
  --libs-only-l                     print required LIBNAME linker flags to stdout
  --libs-only-other                 print required other linker flags to stdout
  --print-requires                  print required dependency frameworks to stdout
  --print-requires-private          print required dependency frameworks for static
                                    linking to stdout
  --print-provides                  print provided dependencies to stdout
  --print-variables                 print all known variables in module to stdout
  --digraph                         print entire dependency graph in graphviz 'dot' format
  --solution                        print dependency graph solution in a simple format
  --keep-system-cflags              keep -I/ucrt64/include entries in cflags output
  --keep-system-libs                keep -L/ucrt64/lib entries in libs output
  --path                            show the exact filenames for any matching .pc files
  --modversion                      print the specified module's version to stdout
  --internal-cflags                 do not filter 'internal' cflags from output
  --license                         print the specified module's license to stdout if known
  --exists-cflags                   add -DHAVE_FOO fragments to cflags for each found module

filtering output:

  --msvc-syntax                     print translatable fragments in MSVC syntax
  --fragment-filter=types           filter output fragments to the specified types
  --env=prefix                      print output as shell-compatible environmental variables
  --fragment-tree                   visualize printed CFLAGS/LIBS fragments as a tree

report bugs to <https://todo.sr.ht/~kaniini/pkgconf>.

no RubyInstaller MSYS2

pkgconf --helpのログ
=== pkgconf --help ===
usage: pkgconf [OPTIONS] [LIBRARIES]

basic options:

  --help                            this message
  --about                           print pkgconf version and license to stdout
  --version                         print supported pkg-config version to stdout
  --verbose                         print additional information
  --atleast-pkgconfig-version       check whether or not pkgconf is compatible
                                    with a specified pkg-config version
  --errors-to-stdout                print all errors on stdout instead of stderr
  --print-errors                    ensure all errors are printed
  --short-errors                    be less verbose about some errors
  --silence-errors                  explicitly be silent about errors
  --list-all                        list all known packages
  --list-package-names              list all known package names
  --simulate                        simulate walking the calculated dependency graph
  --no-cache                        do not cache already seen packages when
                                    walking the dependency graph
  --log-file=filename               write an audit log to a specified file
  --with-path=path                  adds a directory to the search path
  --define-prefix                   override the prefix variable with one that is guessed based on
                                    the location of the .pc file
  --dont-define-prefix              do not override the prefix variable under any circumstances
  --prefix-variable=varname         sets the name of the variable that pkgconf considers
                                    to be the package prefix
  --relocate=path                   relocates a path and exits (mostly for testsuite)
  --dont-relocate-paths             disables path relocation support

cross-compilation personality support:

  --personality=triplet|filename    sets the personality to 'triplet' or a file named 'filename'
  --dump-personality                dumps details concerning selected personality

checking specific pkg-config database entries:

  --atleast-version                 require a specific version of a module
  --exact-version                   require an exact version of a module
  --max-version                     require a maximum version of a module
  --exists                          check whether or not a module exists
  --uninstalled                     check whether or not an uninstalled module will be used
  --no-uninstalled                  never use uninstalled modules when satisfying dependencies
  --no-provides                     do not use 'provides' rules to resolve dependencies
  --maximum-traverse-depth          maximum allowed depth for dependency graph
  --static                          be more aggressive when computing dependency graph
                                    (for static linking)
  --shared                          use a simplified dependency graph (usually default)
  --pure                            optimize a static dependency graph as if it were a normal
                                    dependency graph
  --env-only                        look only for package entries in PKG_CONFIG_PATH
  --ignore-conflicts                ignore 'conflicts' rules in modules
  --validate                        validate specific .pc files for correctness

querying specific pkg-config database fields:

  --define-variable=varname=value   define variable 'varname' as 'value'
  --variable=varname                print specified variable entry to stdout
  --cflags                          print required CFLAGS to stdout
  --cflags-only-I                   print required include-dir CFLAGS to stdout
  --cflags-only-other               print required non-include-dir CFLAGS to stdout
  --libs                            print required linker flags to stdout
  --libs-only-L                     print required LDPATH linker flags to stdout
  --libs-only-l                     print required LIBNAME linker flags to stdout
  --libs-only-other                 print required other linker flags to stdout
  --print-requires                  print required dependency frameworks to stdout
  --print-requires-private          print required dependency frameworks for static
                                    linking to stdout
  --print-provides                  print provided dependencies to stdout
  --print-variables                 print all known variables in module to stdout
  --digraph                         print entire dependency graph in graphviz 'dot' format
  --solution                        print dependency graph solution in a simple format
  --keep-system-cflags              keep -I/ucrt64/include entries in cflags output
  --keep-system-libs                keep -L/ucrt64/lib entries in libs output
  --path                            show the exact filenames for any matching .pc files
  --modversion                      print the specified module's version to stdout
  --internal-cflags                 do not filter 'internal' cflags from output
  --license                         print the specified module's license to stdout if known
  --exists-cflags                   add -DHAVE_FOO fragments to cflags for each found module

filtering output:

  --msvc-syntax                     print translatable fragments in MSVC syntax
  --fragment-filter=types           filter output fragments to the specified types
  --env=prefix                      print output as shell-compatible environmental variables
  --fragment-tree                   visualize printed CFLAGS/LIBS fragments as a tree

report bugs to <https://todo.sr.ht/~kaniini/pkgconf>.

@otegami
Copy link
Contributor Author

otegami commented Nov 28, 2025

I looked into the pkgconf source code. It seems that pkgconf includes Requires.private cflags by default.
The following filtering only happens when the path matches a system include path.

if (!(want_flags & PKG_KEEP_SYSTEM_CFLAGS) && pkgconf_fragment_has_system_dir(client, frag))
    return false;

ref: https://github.com/pkgconf/pkgconf/blob/a1e09753bc4353fdd21957f6c1fd55d7e53662e4/cli/main.c#L136-L137

To match pkgconf's behavior, we need to implement this system path filtering in the pkg-config gem.

@kou
Copy link
Member

kou commented Nov 28, 2025

It seems that pkgconf includes Requires.private cflags by default.

How did you confirm it?

Could you share the result of pkgconf --debug --cflags re2 on both environments? (They will be very large. We may want to redirect the outputs to files and upload them.)

@otegami
Copy link
Contributor Author

otegami commented Nov 28, 2025

I confirmed it using the following information.
In pkgconf_pkg_traverse_main, both Requires and Requires.private are always walked when collecting cflags:

This is also documented in the NEWS file.

  • Document that Requires.private is always used for header paths.

Could you share the result of pkgconf --debug --cflags re2 on both environments? (They will be very large. We may want to redirect the outputs to files and upload them.)

I will check it now.

@kou
Copy link
Member

kou commented Dec 1, 2025

Then, we should keep the current implementation (use Requires.private for shared/static linking), right?

@otegami
Copy link
Contributor Author

otegami commented Dec 1, 2025

Yes. So I will close this PR because this specification doesn't follow pkgconf's behaviors.

@otegami otegami closed this Dec 1, 2025
@otegami otegami deleted the use-requires-private-only-for-static-linking branch December 1, 2025 03:57
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.

2 participants