📄 adding-gnome.html
字号:
> This command will place the grumpalot executable file in the /home/jsheets/wga/bin directory, any libraries in /home/jsheets/wga/lib, and any include files in /home/jsheets/wga/include. When you're done experimenting, you can run make uninstall or rm -rf /home/jsheets/wga. </P><P> Listing 3.15 shows the Makefile.am file for case 2, in which we want to link the two grump source files into a library, then statically link that library into grumpalot. Although this may at first seem a little silly-why don't we just compile them into the executable like we did in case 1?-you may someday have to do this in your own project. If you have a lot of files in your project, you might want to divide some of them up into separate directories to keep things organized and reduce the clutter. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 3.15 Makefile.am for Case 2 of GNOME Grump ExampleINCLUDES = $(GNOME_INCLUDEDIR)bin_PROGRAMS = grumpalotgrumpalot_SOURCES = main.cgrumpalot_LDADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) \ libGrump.lanoinst_LTLIBRARIES = libGrump.lalibGrump_la_SOURCES = grump.c grump_more.clibGrump_la_LIBADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) </PRE></TD></TR></TABLE><P> Unfortunately, GNU make, and thus automake, has a limitation that prevents us from targeting source files outside the current directory. If we were to move grump.c and grump_more.c to a subdirectory, we would have to create an additional Makefile.am file for that subdirectory and then compile those files into a library. Then we could pull that temporary helper library into our main executable by adding it to the grump_LDADD variable in our main Makefile.am file. This is exactly what we'll do in case 2, except without the subdirectory. Our grump_LDADD line will look like this: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">grump_LDADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) \ libGrump.la </PRE></TD></TR></TABLE><P> We name libGrump.la explicitly, without the implicit -l flag, so that the linker will not mistakenly try to link against libGrump.so. We don't have to do anything else to set up the static link. The linker will link libGrump.la into our binary file. Our case 2 grumpalot program won't require any external libraries. automake knows this because we told it to use the noinst target for the library; consequently, the generated makefile will not bother generating any dynamic .so libraries. </P><P> With case 3, we create a dynamic library rather than a static one. This brings up a handful of new concerns. We now have to install the library, since the executable loads it during runtime. We also have to install any header files that define the library's interface. If we didn't install the headers, other people would be unable to use our library because they wouldn't know which functions it contained; more to the point, the compiler needs the header file to satisfy the #include "grump.h" statement in main.c (or it would if the grump library were distributed separately from the main executable). Finally, we should set the library version number as we discussed in Section 3.4.5 to make sure the loader grabs the right library. This is a simple matter of adding the -version-info option to libGrump_la_LDFLAGS. See Listing 3.16 for the case 3 Makefile.am file. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 3.16 Makefile.am for Case 3 of GNOME Grump ExampleINCLUDES = $(GNOME_INCLUDEDIR)bin_PROGRAMS = grumpalotgrumpalot_SOURCES = main.cgrumpalot_LDADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) \ -lGrump -L$(top_builddir)/.libslib_LTLIBRARIES = libGrump.lalibGrump_la_SOURCES = grump.c grump_more.clibGrump_la_LDFLAGS = -version-info 0:0:0libGrump_la_LIBADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS)libgrumpdir = $(includedir)libgrump_HEADERS = grump.h </PRE></TD></TR></TABLE><P> First let's figure out how to make our library shared rather than static. As it turns out, the main thing we have to do is change our noinst_LTLIBRARIES automake variable to lib_LTLIBRARIES. This change tells automake that we want our package's libraries installed in $(libdir). Since we are installing libraries, libtool takes the liberty of generating dynamic .so libraries in addition to the static .a and .la libraries it generated in case 2. Furthermore, it puts these new .so files in the .libs subdirectory rather than in the same directory as the grumpalot executable. For this reason we must add an -L option to grump_LDADD: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">grump_LDADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) \ -lGrump -L$(top_builddir)/.libs </PRE></TD></TR></TABLE><P> We provide this as a relative path off of $(top_builddir) so that make can find the .libs directory even if administrators perform their builds in directories outside of the source tree. This makes it possible to build more than one set of executables with different configure options, simultaneously, off of the same source tree. If you use relative paths inside your source tree, or mistakenly use $(top_srcdir), to refer to your object and library files, you will break this functionality. The linker will end up looking for your object files inside the source tree rather than inside your build tree, where they will reside. </P><P> To see what it's like to build a package outside its source tree, you can create a build directory outside the source tree, cd into it, and invoke the configure script from that directory. configure will create Makefile files inside the build directory (the Makefile.am and Makefile.in files will still land in the source tree). When you run the resulting Makefile, it will create all the object files, libraries, and executables inside the current directory path, in the build directory tree. To see how this works, run all the commands up to and including autoconf inside the source tree, just as you always have. Then type in the following commands (assuming that the myapp subdirectory is the root of your source tree): </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">$ cd ..$ mkdir build$ cd build$ ../myapp/configure$ make$ ./grumpalot </PRE></TD></TR></TABLE><P> The dynamically linked grumpalot executable should now reside inside the build directory. If you wanted to test a static build of grumpalot without pulverizing the current dynamic build, you could create a new directory- buildstatic, for example-and then invoke configure from there, with the --disable-shared option. Presto! You now have two copies of grumpalot on your system-one that dynamically links to libGrump.so, and one that is statically linked to libGrump.a-and both of them arise from the same Makefile.am. </P><P> If you're following along diligently and trying each example at the keyboard as you go, you probably came across a problem in trying to run the dynamically linked case 3 grumpalot executable. Chances are, you got an error that looks something like this: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">$ ./grumpalot./grumpalot: error in loading shared librarieslibGrump.so.0: cannot open shared object file: No such file or directory </PRE></TD></TR></TABLE><P> The problem is that libGrump.so.0 is tucked away in the .libs directory, where your system's loader can't find it. Rather than permanently adding temporary .libs directories to your loader's search path for each project you're testing, you can set the LD_LIBRARY_PATH environment variable to a colon-separated list of extra library paths. To run our case 3 grumpalot executable in the bash shell, for example, you can invoke it like this, in the same directory as grumpalot: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">$ LD_LIBRARY_PATH=.libs ./grumpalot </PRE></TD></TR></TABLE><P> This is only a problem if you try running grumpalot from inside the build tree, prior to installing it. If you've already installed grump with the make install target, things should work fine, as long as you installed it into a path that your system's dynamic link loader knows. </P><P> Our final concern for case 3 is how to install grump.h into the include directory. We can do this in two lines in our Makefile.am file: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">libgrumpdir = $(includedir)libgrump_HEADERS = grump.h </PRE></TD></TR></TABLE><P> The first line creates the arbitrarily named $(libgrumpdir) variable, and sets it to point to $(includedir). This will install all files listed in $(libgrump_HEADERS) into $(includedir). This is good enough for our purposes in case 3. In some projects, however, you may not want all your include files to go into the same directory. You can use a similar approach to place header files into subdirectories of $(includedir), or anywhere else for that matter. For example, if our grump source tree had header files in the subdirectories grump, grump/net, and grump/gui, we could mirror this layout on the target system by adding something like this to our Makefile.am file: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">libgrumpdir = $(includedir)/grumplibgrump_HEADERS = grump.hlibgrumpnetdir = $(includedir)/grump/netlibgrumpnet_HEADERS = grump-net.hlibgrumpguidir = $(includedir)/grump/guilibgrumpgui_HEADERS = grump-gui.h </PRE></TD></TR></TABLE><P> automake would see to it that the corresponding directories were created and that the include files ended up in the proper install location. </P><P> Our final case is a combination of cases 2 and 3, in which we have both static and dynamic libaries in the same project. The case 4 Makefile.am file has the same structure as the one in case 3, except for a few additions (see Listing 3.17). Most notably, we must add a noinst_LTLIBRARIES target to build a new static library from the grump_more.c source file. We'll call this new library libGrumpMore.la. The _SOURCES and _LIBADD primaries for libGrumpMore.la are almost identical to the ones we used for the static library in case 2, except that we are linking only one source file into it. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 3.17 Makefile.am for Case 4 of GNOME Grump ExampleINCLUDES = $(GNOME_INCLUDEDIR)bin_PROGRAMS = grumpalotgrumpalot_SOURCES = main.cgrumpalot_LDADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) \ -lGrump -L$(top_builddir)/.libsnoinst_LTLIBRARIES = libGrumpMore.lalib_LTLIBRARIES = libGrump.lalibGrump_la_DEPENDENCIES = libGrumpMore.lalibGrump_la_SOURCES = grump.clibGrump_la_LDFLAGS = -version-info 0:0:0libGrump_la_LIBADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS) \ libGrumpMore.lalibGrumpMore_la_SOURCES = grump_more.clibGrumpMore_la_LIBADD = $(GNOME_LIBDIR) $(GNOMEUI_LIBS)libgrumpdir = $(includedir)libgrump_HEADERS = grump.h </PRE></TD></TR></TABLE><P> The library targets will need a little work to convert them from case 3 to case 4, but not much. First we remove grump_more.c from libGrump_la_SOURCES, since it now resides in the libGrumpMore.la library. Next we add libGrumpMore.la to libGrump_la_LIBADD, just as we added the static libGrump.la to grump_LDADD in case 2. As a result, the linker will statically link libGrumpMore.la into libGrump.la so that we end up with only one distributable library. </P><P> Our final tweak addresses a timing issue with the order of compilation. We must make sure that our makefile creates libGrumpMore.la before it tries to create libGrump.la. Simply adding libGrumpMore.la to the libGrump.la link line is not enough to generate a dependency check. We must state the dependency explicitly, or we will have no guarantee that libGrumpMore.la will exist when libGrump.la needs it. We can do this with automake's _DEPENDENCIES primary: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">libGrump_la_DEPENDENCIES = libGrumpMore.la </PRE></TD></TR></TABLE><P> The _DEPENDENCIES primary simply adds its contents to the list of dependencies for the libGrump.la target in the makefile, forcing make to build our libGrumpMore.la file first. </P></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="dealing-with-libraries.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="graphics.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Dealing with Libraries</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="gnome-build.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Graphics</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -