Chapter:C libraries Exercises

From Juneday education
Jump to: navigation, search

Introducing media manager (again)

We're going to reuse the code from the chapter on dynamic memory. We've copied the code to a separate directory, libraries/media-files in the repo programming-with-c at github.

You should use the following flags when compiling: -pedantic -Wconversion -Wall -Werror -Wextra -Wstrict-prototypes . We suggest you use a variable CFLAGS, like this:

$ CFLAGS="-pedantic -Wconversion -Wall -Werror -Wextra -Wstrict-prototypes" 
gcc $CFLAGS .... your other arguments

The c files providing the media file functionality are: lib/medialist.c, lib/media-printer.c, lib/mediafile-reader.c and the c file with the main function is: main/media-manager.c

The files in the lib directory to be a separate module managerd by a separate team. It's not much of team considering the small amount of code, but let's pretend the code base is way bigger. Another team is responsible for the program, located in the main directory. In our company there's also a groupd of people writing a graphical user interface which is using the "library". So to sum things up, these are our separate software modules, each managed by a separate team:

  • library
  • cli (command line interface) program
  • gui program

We are going to use these assumptions in the questions below where we will discuss the implications a change in the "library" will have. In the sections with questions about archive ans shared library we will also assume that the library (archive or shared) are installed along with the header files at the customer's site.

Exercises on not using any kind of library

Create a program from all the c files

Compile the c files and create a program, media-manager

Expand using link to the right to see a possible solution/answer.

Suggested solution

$ gcc -c $CFLAGS -Ilib -Imain main/media-manager.c -o main/media-manager.o
$ gcc -c $CFLAGS -Ilib -Imain lib/mediafile-reader.c -o lib/mediafile-reader.o
$ gcc -c $CFLAGS -Ilib -Imain lib/medialist.c -o lib/medialist.o
$ gcc -c $CFLAGS -Ilib -Imain lib/media-printer.c -o lib/media-printer.o
$ gcc  main/media-manager.o lib/*.o -o main/media-manager

How big are the object files?

How big are the object files, including main/media-manager.o?

Expand using link to the right to see a possible solution/answer.

Suggested solution

$ du -scb lib/*.o main/*.o
2488	lib/mediafile-reader.o
3520	lib/medialist.o
2336	lib/media-printer.o
1712	main/media-manager.o
10056	total

So 10056 in total.

How big is the program?

Expand using link to the right to see a possible solution/answer.

Suggested solution

$ du -scb main/media-manager
13368	main/media-manager
13368	total

So 13368.

What are the implications on updating the "lib"?

If the two programs are installed at a customer, what softwares need to be recompiled and reinstalled at the customers site?

Expand using link to the right to see a suggested solution/answer.

Both programs. Since the programs both depend on the library's code and that code is linked in compile time (well, actually during the linking phase) the programs need to be both recompiled (and linked) and reinstalled.

What shared libraries is the program linked to?

Use the program ldd to find which shared libraries are required by the program.

Expand using link to the right to see a suggested solution/answer.

$ ldd ./main/media-manager
	linux-vdso.so.1 (0x00007fff4c73d000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f1939cf7000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f193a0dc000)

The program requires:

  • linux-vdso.so.1
  • libc.so.6
  • /lib64/ld-linux-x86-64.so.2

It is quite easy to deduct that linux-vdso.so.1 and /lib64/ld-linux-x86-64.so.2 are Linux related. Since the authors of the books at wiki.juneday.se use GNU/Linux. What about the library libc.so.6? C programs, on most operating systems, typically link against a library called libc.

Exercises on static archives

In this section we will, apart from the previous assumptions, that the customer also get the archive and header files installed.

Create an archive from the c files in lib

Compile the c files in the lib directory and create an archive.

Expand using link to the right to see a suggested solution/answer.

Create the archive:

$ gcc -c $CFLAGS -Ilib lib/mediafile-reader.c -o lib/mediafile-reader.o
$ gcc -c $CFLAGS -Ilib lib/medialist.c -o lib/medialist.o
$ gcc -c $CFLAGS -Ilib lib/media-printer.c -o lib/media-printer.o
$ ar rcu lib/libmedia.a lib/mediafile-reader.o lib/medialist.o lib/media-printer.o

Explanations:

  • the first three lines compiles the c files into objects files
  • the fourth line creates an archive libmedia.a in the directory lib

Create a program from the c file and an archive

Compile the c files and link the program, media-manager, against the archive.

Expand using link to the right to see a suggested solution/answer.

Compile and link the program (against the archive):

$ gcc -c $CFLAGS -Ilib -Imain main/media-manager.c -o main/media-manager.o
$ gcc  main/media-manager.o -Llib -lmedia -o main/media-manager

Explanations:

  • the first line compiles the c file (main/media-manager.c) to an object files (main/media-manager.o)
  • the second line links the object file (main/media-manager.c) with the archive libmedia.a
    • -Llib to tell the linker where to look for the archive libarchive.a.
    • -lmedia instructs the linker to look for an archive called libarchive.a (or shared library called libarchive.so)

How big are the object files?

How big are the object files, including main/media-manager.o?

Expand using link to the right to see a suggested solution/answer.

$ du -sbc lib/*.o
2440	lib/mediafile-reader.o
3520	lib/medialist.o
2336	lib/media-printer.o
8296	total

That is 8296 bytes in total.

How big is the archive (with the object files)?

How big is the archive consisting of the object files, excluding main/media-manager.o?

Expand using link to the right to see a suggested solution/answer.

$ du -sb lib/libmedia.a 
8814	lib/libmedia.a

That is 8296 bytes.

How big is the program?

How big is the program? Compare this to the size of the archive and the program's coresponding object file.

Expand using link to the right to see a suggested solution/answer.

$ du -sb main/media-manager
13368	main/media-manager

That is, the program is 13368 bytes big.

$ du -sbc main/media-manager.o lib/libmedia.a 
1672	main/media-manager.o
8814	lib/libmedia.a
10486	total

That is, the program's object file and the archive are 10486 bytes big in total.

There's a difference between the size of the program and the object files (the program's object files and the archive). This can be explained with the extra code needed to make the program executable.

For the keen student it is possible to see what's in the binary NOT being the archive or the program's stuff (originating from the file main/media-manager.c). We can use nm to list the symbols in the program and "grep away" the symbols from the archive and the program's c code.

$ nm main/media-manager | grep -v " U " | grep -v media | grep -v read_from | grep -v return_codes

Explanation:

  • nm main/media-manager - list the symbols in the program
  • grep -v " U " - filter out the undefined symbols
  • grep -v media - filter out the things with media in the name
  • grep -v read_from - filter out the things with read_from in the name
  • grep -v return_codes - filter out the symbols with return_codes in the name

Using this we'll get a list of the symbols added by the linker:

$ nm main/media-manager | grep -v " U " | grep -v media | grep  -v read_from | grep -v return_codes
000000000060206c B __bss_start
0000000000602088 b completed.6973
0000000000602068 D __data_start
0000000000602068 W data_start
0000000000400770 t deregister_tm_clones
00000000004007e0 t __do_global_dtors_aux
0000000000601e10 t __do_global_dtors_aux_fini_array_entry
0000000000400f68 R __dso_handle
0000000000601e18 d _DYNAMIC
000000000060206c D _edata
0000000000602090 B _end
0000000000400f54 T _fini
0000000000400810 t frame_dummy
0000000000601e08 t __frame_dummy_init_array_entry
00000000004012dc r __FRAME_END__
0000000000602000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000401054 r __GNU_EH_FRAME_HDR
0000000000400678 T _init
0000000000601e10 t __init_array_end
0000000000601e08 t __init_array_start
0000000000400f60 R _IO_stdin_used
0000000000400f50 T __libc_csu_fini
0000000000400ee0 T __libc_csu_init
0000000000400817 T main
00000000004007a0 t register_tm_clones
0000000000400740 T _start
0000000000602080 B stdin@@GLIBC_2.2.5
0000000000602070 B stdout@@GLIBC_2.2.5
0000000000602070 D __TMC_END__

Quite a lot isn't it.

What does the customer need to use the "lib" code?

Expand using link to the right to see a suggested solution/answer.

The customer obviously needs the archive itself. Apart from that the customer need the header files. Without them the compiler will make assumptions about the code in the archive. These assumptions will not be correct and you'll get tons of warnings and most likely errors.

What are the implications on updating the "lib" code?

If we update the code in the library (currently compiled as an archive). What action do we need to take to let the customer have the latest version of everything.

Expand using link to the right to see a suggested solution/answer.

The customer needs the following from us:

  • the new/updated archive
  • the new/updated header files
  • a new/updated cli linked against the new archive
  • a new/updated gui linked against the new archive

The customer needs to do the following:

  • every software the customer has developed, using the library (currently an archive), need to be linked against the new/updated version of the archive.

Exercises on shared libraris

In this section we will, apart from the previous assumptions, that the customer also get a shared library, instead of an archive, and header files installed.

Create a shared library from the c files in lib

Compile the c files in the lib directory and create a shared library.

Expand using link to the right to see a suggested solution/answer.

Create the archive:

$ gcc -c $CFLAGS -Ilib lib/mediafile-reader.c -o lib/mediafile-reader.o
$ gcc -c $CFLAGS -Ilib lib/medialist.c -o lib/medialist.o
$ gcc -c $CFLAGS -Ilib lib/media-printer.c -o lib/media-printer.o
$ gcc -shared lib/mediafile-reader.o lib/medialist.o lib/media-printer.o -o lib/libmedia.so

Explanations:

  • the first three lines compiles the c files into objects files
  • the fourth line creates a shared library libmedia.so in the directory lib

Create a program from the c file and link against the shared library

Compile the c files and link the program, media-manager, against the shared library.

Expand using link to the right to see a suggested solution/answer.

Compile and link the program (against the shared library):

$ gcc -c $CFLAGS -Ilib -Imain main/media-manager.c -o main/media-manager.o
$ gcc  main/media-manager.o -Llib -lmedia -o main/media-manager

Explanations:

  • the first line compiles the c file (main/media-manager.c) to an object files (main/media-manager.o)
  • the second line links the object file (main/media-manager.c) with the shared library libmedia.so
    • -Llib to tell the linker where to look for the shared library libarchive.so.
    • -lmedia instructs the linker to look for an library called libarchive.a or shared library called libarchive.so

What does the linker chose: archive or shared library?

Let's create an archive as well as a shared library.

$ gcc -c $CFLAGS -Ilib lib/mediafile-reader.c -o lib/mediafile-reader.o
$ gcc -c $CFLAGS -Ilib lib/medialist.c -o lib/medialist.o
$ gcc -c $CFLAGS -Ilib lib/media-printer.c -o lib/media-printer.o
$ ar rcu lib/libmedia.a lib/mediafile-reader.o lib/medialist.o lib/media-printer.o
$ gcc -shared lib/mediafile-reader.o lib/medialist.o lib/media-printer.o -o lib/libmedia.so

Let's continue with creating a program with the command we've used above (to link):

$ gcc  main/media-manager.o -Llib -lmedia -o main/media-manager

What library did the linker choose: archive or shared library?

Expand using link to the right to see a suggested solution/answer.

Let's use ldd to see what shared libraries the program require:

$ ldd main/media-manager
	linux-vdso.so.1 (0x00007ffc8f9e6000)
	libmedia.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f2fa932b000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f2fa9710000)

This tells us that libmedia.so is required.

We could also check the symbols in the program.

$ nm main/media-manager|  grep media
                 U free_medialist
                 U print_medialist
                 U read_media_user

No symbols with "media" in the name is defined in the program, so it can't be an archive.


Link against the archive

Let's use a slighlty different link directive.

$ gcc main/media-manager.o -Llib -l:libmedia.a -o main/media-manager

What library did the linker choose: archive or shared library?

Expand using link to the right to see a suggested solution/answer.

Let's use ldd to see what shared libraries the program require:

$ ldd main/media-manager
	linux-vdso.so.1 (0x00007ffdacb19000)
	libc.so.6 => /lib64/libc.so.6 (0x00007ff454f5d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ff455342000)

This tells us that libmedia.so is NOTrequired.

We could also check the symbols in the program.

$ nm main/media-manager|  grep media
0000000000400bdd T add_mediafile
0000000000400d22 T free_medialist
0000000000400cef T init_medialist
0000000000400d5d T print_mediafile
0000000000400e47 T print_medialist
0000000000400931 T read_media_user
0000000000400b7c t realloc_mediafile
00000000004009c9 T set_mediafile

Lots of symbols with "media" in the name is defined in the program, so the program is linked against the archive.


Link against the shared library

Let's use a slighlty different link directive.

$ $ gcc -Wl,-Bdynamic main/media-manager.o -Llib -lmedia -o main/media-manager

What library did the linker choose: archive or shared library?

Expand using link to the right to see a suggested solution/answer.

Let's use ldd to see what shared libraries the program require:

$ ldd main/media-manager
	linux-vdso.so.1 (0x00007ffc8f9e6000)
	libmedia.so => not found
	libc.so.6 => /lib64/libc.so.6 (0x00007f2fa932b000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f2fa9710000)

This tells us that libmedia.so is required.

We could also check the symbols in the program.

$ nm main/media-manager|  grep media
                 U free_medialist
                 U print_medialist
                 U read_media_user

No symbols with "media" in the name is defined in the program, so it can't be an archive.

How big are the object files?

How big are the object files, including main/media-manager.o?

Expand using link to the right to see a suggested solution/answer.

$ du -sbc lib/*.o
2440	lib/mediafile-reader.o
3520	lib/medialist.o
2336	lib/media-printer.o
8296	total

That is 8296 bytes in total.

How big is the shared library (with the object files)?

How big is the shared library consisting of the object files (excluding main/media-manager.o)?

Expand using link to the right to see a suggested solution/answer.

$ du -sb lib/libmedia.so 
13008	lib/libmedia.so

That is 13008 bytes.

How big is the program?

How big is the program?

Expand using link to the right to see a suggested solution/answer.

$ du -sb main/media-manager
8352	main/media-manager

That is, the program is 8352 bytes big.

What does the customer need to use the "lib" code?

Expand using link to the right to see a suggested solution/answer.

The customer obviously needs the shared library itself. Apart from that the customer need the header files. Without them the compiler will make assumptions about the code in the shared library. These assumptions will not be correct and you'll get tons of warnings and most likely errors.

What are the implications on updating the "lib" code?

If we update the code in the library (currently compiled as an shared library). What action do we need to take to let the customer have the latest version of everything.

Expand using link to the right to see a suggested solution/answer.

The customer needs the following from us:

  • the new/updated shared lib
  • the new/updated header files

The customer does NOT need the following from us:

  • a new/updated cli linked against the new archive
  • a new/updated gui linked against the new archive

The customer needs to do the following:

  • every software the customer has developed, using the library (currently an shared library), need to be linked in runtime against the new/updated version of the shared library, so the only thing needed is to deploy the new shared library.