Merge branch 'cflags-private' into 'master'

Add Cflags.private field — required for linking on Windows

Closes #38

See merge request pkg-config/pkg-config!13
This commit is contained in:
Oneric 2021-09-30 17:12:57 +00:00
commit 55e41a9e4a
10 changed files with 185 additions and 59 deletions

View file

@ -2,6 +2,7 @@ TESTS_ENVIRONMENT = PKG_CONFIG='$(TESTS_PKG_CONFIG)' $(TESTS_SHELL)
TESTS = \
check-cflags \
check-cflags-private \
check-libs \
check-mixed-flags \
check-non-l-flags \
@ -40,6 +41,7 @@ EXTRA_DIST = \
requires-test.pc \
public-dep.pc \
private-dep.pc \
private-cflags.pc \
includedir.pc \
missing-requires-private.pc \
missing-requires.pc \

11
check/check-cflags-private Executable file
View file

@ -0,0 +1,11 @@
#! /bin/sh
set -e
. ${srcdir}/common
RESULT="-I/dummy/include"
run_test --cflags private-cflags
RESULT="-DDUMMY_STATIC=1 $RESULT"
run_test --static --cflags private-cflags

7
check/private-cflags.pc Normal file
View file

@ -0,0 +1,7 @@
Name: Requires test package
Description: Dummy pkgconfig test package for testing Cflags/Cflags.private
Version: 1.0.0
Libs: -L/dummy/lib -ldummy
Cflags: -I/dummy/include
Cflags.private: -DDUMMY_STATIC=1

10
main.c
View file

@ -615,9 +615,15 @@ main (int argc, char **argv)
debug_spew ("Error printing disabled\n");
if (want_static_lib_list)
enable_private_libs();
{
enable_libs_private();
enable_cflags_private();
}
else
disable_private_libs();
{
disable_libs_private();
disable_cflags_private();
}
/* honor Requires.private if any Cflags are requested or any static
* libs are requested */

145
parse.c
View file

@ -798,40 +798,9 @@ parse_libs_private (Package *pkg, const char *str, const char *path)
}
static void
parse_cflags (Package *pkg, const char *str, const char *path)
_do_parse_cflags (Package *pkg, int argc, char **argv)
{
/* Strip out -I flags, put them in a separate list. */
char *trimmed;
char **argv = NULL;
int argc = 0;
GError *error = NULL;
int i;
if (pkg->cflags)
{
verbose_error ("Cflags field occurs twice in '%s'\n", path);
if (parse_strict)
exit (1);
else
return;
}
trimmed = trim_and_sub (pkg, str, path);
if (trimmed && *trimmed &&
!g_shell_parse_argv (trimmed, &argc, &argv, &error))
{
verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n",
error ? error->message : "unknown");
if (parse_strict)
exit (1);
else
{
g_free (trimmed);
return;
}
}
i = 0;
while (i < argc)
@ -881,14 +850,103 @@ parse_cflags (Package *pkg, const char *str, const char *path)
g_free (flag);
g_free (arg);
++i;
}
}
static void
parse_cflags (Package *pkg, const char *str, const char *path)
{
/* Strip out -I flags, put them in a separate list. */
char *trimmed;
char **argv = NULL;
int argc = 0;
GError *error = NULL;
if (pkg->cflags)
{
verbose_error ("Cflags field occurs twice in '%s'\n", path);
if (parse_strict)
exit (1);
else
return;
}
trimmed = trim_and_sub (pkg, str, path);
if (trimmed && *trimmed &&
!g_shell_parse_argv (trimmed, &argc, &argv, &error))
{
verbose_error ("Couldn't parse Cflags field into an argument vector: %s\n",
error ? error->message : "unknown");
if (parse_strict)
exit (1);
else
{
g_free (trimmed);
return;
}
}
_do_parse_cflags(pkg, argc, argv);
g_strfreev (argv);
g_free (trimmed);
}
static void
parse_cflags_private (Package *pkg, const char *str, const char *path)
{
/*
List of private Cflags. Private Cflags are flags which
are needed in the case of static linking. This can be required for
example on platforms which require special attributes to be set
for variables or functions which are defined in a shared library,
as is the case for Microsoft Windows. Affected libraries will need
to have ifdefs in their public headers to change the attributes
depending on whether they are being linked to staticly or dynamicly.
*/
char *trimmed;
char **argv = NULL;
int argc = 0;
GError *error = NULL;
if (pkg->cflags_private_num)
{
verbose_error ("Cflags.private field occurs twice in '%s'\n", path);
if (parse_strict)
exit (1);
else
return;
}
trimmed = trim_and_sub (pkg, str, path);
if (trimmed && *trimmed &&
!g_shell_parse_argv (trimmed, &argc, &argv, &error))
{
verbose_error ("Couldn't parse Cflags.private field into an argument vector: %s\n",
error ? error->message : "unknown");
if (parse_strict)
exit (1);
else
{
g_free (trimmed);
return;
}
}
_do_parse_cflags(pkg, argc, argv);
g_strfreev (argv);
g_free (trimmed);
pkg->cflags_private_num++;
}
static void
parse_url (Package *pkg, const char *str, const char *path)
{
@ -906,8 +964,8 @@ parse_url (Package *pkg, const char *str, const char *path)
static void
parse_line (Package *pkg, const char *untrimmed, const char *path,
gboolean ignore_requires, gboolean ignore_private_libs,
gboolean ignore_requires_private)
gboolean ignore_requires, gboolean ignore_libs_private,
gboolean ignore_requires_private, gboolean ignore_cflags_private)
{
char *str;
char *p;
@ -964,7 +1022,7 @@ parse_line (Package *pkg, const char *untrimmed, const char *path,
}
else if (strcmp (tag, "Libs.private") == 0)
{
if (!ignore_private_libs)
if (!ignore_libs_private)
parse_libs_private (pkg, p, path);
}
else if (strcmp (tag, "Libs") == 0)
@ -972,6 +1030,12 @@ parse_line (Package *pkg, const char *untrimmed, const char *path,
else if (strcmp (tag, "Cflags") == 0 ||
strcmp (tag, "CFlags") == 0)
parse_cflags (pkg, p, path);
else if (strcmp (tag, "Cflags.private") == 0 ||
strcmp (tag, "CFlags.private") == 0)
{
if (!ignore_cflags_private)
parse_cflags_private (pkg, p, path);
}
else if (strcmp (tag, "Conflicts") == 0)
parse_conflicts (pkg, p, path);
else if (strcmp (tag, "URL") == 0)
@ -1088,8 +1152,9 @@ parse_line (Package *pkg, const char *untrimmed, const char *path,
Package*
parse_package_file (const char *key, const char *path,
gboolean ignore_requires,
gboolean ignore_private_libs,
gboolean ignore_requires_private)
gboolean ignore_libs_private,
gboolean ignore_requires_private,
gboolean ignore_cflags_private)
{
FILE *f;
Package *pkg;
@ -1133,8 +1198,8 @@ parse_package_file (const char *key, const char *path,
{
one_line = TRUE;
parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs,
ignore_requires_private);
parse_line (pkg, str->str, path, ignore_requires, ignore_libs_private,
ignore_requires_private, ignore_cflags_private);
g_string_truncate (str, 0);
}

View file

@ -24,8 +24,9 @@
Package *parse_package_file (const char *key, const char *path,
gboolean ignore_requires,
gboolean ignore_private_libs,
gboolean ignore_requires_private);
gboolean ignore_libs_private,
gboolean ignore_requires_private,
gboolean ignore_cflags_private);
GList *parse_module_list (Package *pkg, const char *str, const char *path);

View file

@ -137,6 +137,13 @@ Libs: -L${libdir} -lfoo</pre>
libraries support <tt>pkg-config</tt>, they should be added to
<tt>Requires</tt> or <tt>Requires.private</tt>.</li>
<li><b>Cflags.private</b>: The compiler flags specific to the static version
of your package. This may be required if your public headers need to change
according to linkage mode, as is for example the case on Microsoft Windows
if a library exposes a variable.
Don't add any flags for required packages supporting <tt>pkg-config</tt>;
<tt>pkg-config</tt> will add those automatically.</li>
<li><b>Libs</b>: The link flags specific to this package and any required
libraries that don't support <tt>pkg-config</tt>. The same rule as
<tt>Cflags</tt> applies here.</li>
@ -186,8 +193,9 @@ includedir=${prefix}/include
Cflags: -I${includedir}/foo</pre>
<p>The most important <tt>pkg-config</tt> metadata fields are
<tt>Requires</tt>, <tt>Requires.private</tt>, <tt>Cflags</tt>, <tt>Libs</tt>
and <tt>Libs.private</tt>. They will define the metadata used by external
<tt>Requires</tt>, <tt>Requires.private</tt>, <tt>Cflags</tt>, <tt>Cflags.private</tt>
<tt>Libs</tt> and <tt>Libs.private</tt>.
They will define the metadata used by external
projects to compile and link with the library.</p>
<p><tt>Requires</tt> and <tt>Requires.private</tt> define other modules
@ -214,9 +222,9 @@ Cflags: -I${includedir}/foo</pre>
additional direct dependency.</p>
<p>Finally, the <tt>Cflags</tt> contains the compiler flags for using the
library. Unlike the <tt>Libs</tt> field, there is not a private variant of
<tt>Cflags</tt>. This is because the data types and macro definitions are
needed regardless of the linking scenario.</p>
library. <tt>Cflags.private</tt> contain compiler flags specific to only the
static version of the library; they will be used in addition to the regular
<tt>Cflags</tt> if <tt>--static</tt> is set.</p>
<h2><a name="using">Using pkg-config files</a></h2>

View file

@ -629,6 +629,14 @@ installed.
This line should list the compile flags specific to your package.
Don't add any flags for required packages; \fIpkg-config\fP will
add those automatically.
.TP
.I "Cflags.private:"
This line should list the compile flags specific to the static version
of your package. This may be required if your public headers need to change
according to linkage mode, as is for example the case on Microsoft Windows
if a library exposes a variable.
Don't add any flags for required packages; \fIpkg-config\fP will
add those automatically.
.\"
.SH AUTHOR

31
pkg.c
View file

@ -49,7 +49,8 @@ static GList *search_dirs = NULL;
gboolean disable_uninstalled = FALSE;
gboolean ignore_requires = FALSE;
gboolean ignore_requires_private = TRUE;
gboolean ignore_private_libs = TRUE;
gboolean ignore_libs_private = TRUE;
gboolean ignore_cflags_private = TRUE;
void
add_search_dir (const char *path)
@ -300,7 +301,8 @@ internal_get_package (const char *name, gboolean warn)
debug_spew ("Reading '%s' from file '%s'\n", name, location);
pkg = parse_package_file (key, location, ignore_requires,
ignore_private_libs, ignore_requires_private);
ignore_libs_private, ignore_requires_private,
ignore_cflags_private);
g_free (key);
if (pkg != NULL && strstr (location, "uninstalled.pc"))
@ -950,7 +952,7 @@ packages_get_flags (GList *pkgs, FlagType flags)
}
if (flags & LIBS_L)
{
cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_private_libs);
cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_libs_private);
debug_spew ("adding LIBS_L string \"%s\"\n", cur);
g_string_append (str, cur);
g_free (cur);
@ -958,7 +960,7 @@ packages_get_flags (GList *pkgs, FlagType flags)
if (flags & (LIBS_OTHER | LIBS_l))
{
cur = get_multi_merged (pkgs, flags & (LIBS_OTHER | LIBS_l), FALSE,
!ignore_private_libs);
!ignore_libs_private);
debug_spew ("adding LIBS_OTHER | LIBS_l string \"%s\"\n", cur);
g_string_append (str, cur);
g_free (cur);
@ -1181,6 +1183,7 @@ print_package_list (void)
ignore_requires = TRUE;
ignore_requires_private = TRUE;
ignore_cflags_private = TRUE;
/* Add the packages to a pointer array and sort by pkg->key first, to give
* deterministic output. While doing that, work out the maximum key length
@ -1212,15 +1215,15 @@ print_package_list (void)
}
void
enable_private_libs(void)
enable_libs_private(void)
{
ignore_private_libs = FALSE;
ignore_libs_private = FALSE;
}
void
disable_private_libs(void)
disable_libs_private(void)
{
ignore_private_libs = TRUE;
ignore_libs_private = TRUE;
}
void
@ -1246,3 +1249,15 @@ disable_requires_private(void)
{
ignore_requires_private = TRUE;
}
void
enable_cflags_private(void)
{
ignore_cflags_private = FALSE;
}
void
disable_cflags_private(void)
{
ignore_cflags_private = TRUE;
}

7
pkg.h
View file

@ -84,6 +84,7 @@ struct Package_
int path_position; /* used to order packages by position in path of their .pc file, lower number means earlier in path */
int libs_num; /* Number of times the "Libs" header has been seen */
int libs_private_num; /* Number of times the "Libs.private" header has been seen */
int cflags_private_num; /* Number of times the "Cflags.private" header has been seen */
char *orig_prefix; /* original prefix value before redefinition */
};
@ -116,12 +117,14 @@ void verbose_error (const char *format, ...);
gboolean name_ends_in_uninstalled (const char *str);
void enable_private_libs(void);
void disable_private_libs(void);
void enable_libs_private(void);
void disable_libs_private(void);
void enable_requires(void);
void disable_requires(void);
void enable_requires_private(void);
void disable_requires_private(void);
void enable_cflags_private(void);
void disable_cflags_private(void);
/* If TRUE, do not automatically prefer uninstalled versions */
extern gboolean disable_uninstalled;