chapter15-linking_to_sdl2.txt 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. ===========================
  2. Chapter 15: linking to SDL2
  3. ===========================
  4. What you need to know before you read this:
  5. * Linux: bash shell
  6. * Linux: text editors
  7. * Linux: exit code
  8. * Linux: man pages
  9. * Git: repositories
  10. * Git: clone
  11. * Git: commits
  12. * Programming: libraries
  13. * C programming: functions
  14. * C programming: function arguments
  15. * C programming: command line arguments
  16. * C preprocessor: #include
  17. * C library: printf()
  18. * GCC: compiling stage
  19. * GCC: linking stage
  20. What this chapter will teach you:
  21. * GCC: link to external library
  22. * SDL2: SDL_Delay
  23. * ldd: show links
  24. Projects worked on:
  25. * Cuterald
  26. Repo: http://hqetojnktk6trragksiuszsodbuszhmekulsbtp2bfumvh3i7sfiyoyd.onion:80/Maple/cuterald.git
  27. Current commit: 9c3a2e731ec03644bd7f0c92cca3e91d4d04aec4
  28. Section I: fetch or pull the reference repository
  29. -------------------------------------------------
  30. What follows is a quick reminder on how to pull my version of the code that we expect to start with
  31. this chapter. There's benefit in knowing how to do this - your code might diverge from mine and
  32. cause some bugs that don't happen on the "canonical" version. I encourage working on your own code
  33. and experimenting as you wish, but if you ever run into problems or errors that you can't figure
  34. out, it helps to have a reference that is known to work so you can compare things.
  35. What needs to be done depends on how when (or if) you've had interactions with the repository
  36. before.
  37. * Scenario 1: you never pulled the repo
  38. If you never pulled my code at all, follow these steps:
  39. 1. Navigate from bash (or another shell) to the folder where you want to put the project folder.
  40. 2. Run `torsocks clone <repo>`, where '<repo>' is the URL you see in the header for this chapter,
  41. without the greater than / less than signs.
  42. 3. A new directory is present (in this case, "cuterald"). Enter it.
  43. 4. Run git checkout on the hash I've provided.
  44. * Scenario 2: you already have a copy
  45. 1. Navigate, in your shell, to the folder where the example code lives.
  46. 2. Run `torsocks git fetch` to make sure all commits from the remote are available to you.
  47. Fetch talks to the remote and gets all data from it, but doesn't do anything with it yet.
  48. 3. Run git checkout on the hash I've provided.
  49. In both scenarios, the last step is to checkout the commit (using the provided hash). That updates
  50. your working directory (the code you actually work on) with the version present in that commit.
  51. To do the checkout, run `git checkout <commit>`, where '<commit>' is the hash I've provided. For
  52. this chapter, the hash is 9c3a2e731ec03644bd7f0c92cca3e91d4d04aec4.
  53. You may have changes in your working copy. Sometimes Git can cleverly merge them, but often it will
  54. complain that a checkout can't be done because it would overwrite those files. Git also doesn't
  55. care about files that you added but didn't include in any commit yet. Because of this, it's good
  56. practice to run `git status` after a checkout to verify that the repo is clean.
  57. If your local copy is screwed up and you can't get the checkout command to work, the easiest way to
  58. fix it is by simply deleting the entire repository and just re-cloning (ie, following the
  59. instructions for scenario 1). Nuke and restart is generally not a great practice, but since Git can
  60. be quite complicated and we've only covered the very basics, it's perfectly forgivable to sidestep
  61. all that and keeping it simple.
  62. Section II: write a basic main function
  63. ---------------------------------------
  64. A good first step to starting any new project is to start with the simplest possible starting
  65. point. As such, we'll write a quick main function that doesn't do anything yet, but compiles
  66. properly.
  67. The absolute base requirements for any functioning C program is simply that main is present. So you
  68. could start with just this code:
  69. - main.c ---
  70. int main(){}
  71. ------------
  72. However, in the interest of completeness, let's make sure it can take arguments and also returns
  73. success back to the operating system. Always keep it clean!
  74. --------------------- main.c ---
  75. int main (int argc, char** argv)
  76. {
  77. return 0;
  78. }
  79. --------------------------------
  80. Compile and run it. This is your sanity check - if compilation fails on a basic program like this,
  81. you either screwed up, or something is wrong with your system. Don't continue until compilation
  82. works, the problem will not magically disappear.
  83. Section III: finding SDL2 documentation
  84. ---------------------------------------
  85. SDL2 is a product for programmers, and as such it has a manual. Manuals come in many shapes and
  86. sizes. For SDL, the easiest to use ones are the man pages, and the wiki.
  87. * Wiki
  88. URL: https://wiki.libsdl.org/
  89. The wiki is the easiest to use when you're online, and can be used from any system. It also has
  90. the benefit of having tutorials, easy to use navigation, and a search bar.
  91. Try, for example, searching for SDL_Delay, and you'll be brought to this page:
  92. https://wiki.libsdl.org/SDL_Delay
  93. * Linux man pages
  94. This requires that you have SDL2 actually installed (and some distributions may package the man
  95. pages separately), but is by far the fastest way to get information.
  96. Just run `man` followed by any SDL function you want to know about (example: `man SDL_Delay`) to
  97. get the information for that function.
  98. Both approaches will give you the information you need for anything you use in SDL2. For functions,
  99. that means it'll give you a list of what the function does, what it returns, and what you need to
  100. pass it.
  101. Beyond the wiki and man pages, there's also plenty of tutorials and support forums. Whenever you
  102. have a problem that's not covered here, try just describing it in a search engine, and you'll almost
  103. always find someone who had a similar problem, and some potential solutions to try.
  104. Section IV: waiting with SDL_Delay
  105. ----------------------------------
  106. SDL_Delay is one of the simplest functions you can use in SDL2. It's a function that does nothing
  107. but wait a certain amount of time. It sounds useless, but it's used in almost every SDL program.
  108. Open the documentation here, and I'll walk you through it:
  109. https://wiki.libsdl.org/SDL_Delay
  110. You'll see that the syntax is described as such:
  111. -------------------------
  112. void SDL_Delay(Uint32 ms)
  113. -------------------------
  114. As a reminder - that means the function name is SDL_Delay, it returns nothing (void), and requires
  115. milliseconds as an input. You're not yet familiar with Uint32. It's a custom type defined by SDL2
  116. itself. You'll learn how to make custom types yourself and that'll help you understand this. For
  117. now, just know that you can pass any positive number to it.
  118. The documentation will tell you what you need to know - SDL_Delay just waits the specified amount
  119. of milliseconds. Try updating your code to look something like this:
  120. ===================== main.c ===
  121. #include <SDL2/SDL_timer.h>
  122. int main (int argc, char** argv)
  123. {
  124. SDL_Delay(3000);
  125. return 0;
  126. }
  127. ================================
  128. This won't compile yet - you'll see a linker error. We'll fix that in the next section.
  129. Like any other function, SDL_Delay can be called anywhere in your program, so long as it's declared
  130. in advance. SDL2 organizes all its header files into the SDL2 subfolder.
  131. On most systems, all standard header files can be found in /usr/include. That includes the ones for
  132. the standard C library - take a look at stdio.h, which provides printf for you. There's also quite
  133. a few subfolders in there, depending on what you have installed on your system.
  134. SDL2 has a subfolder in there: /usr/include/SDL2. Try to list the files in there, and you'll see
  135. that SDL_timer.h is in there as well. When gcc searches for header files, it checks a couple
  136. places, including /usr/include. However, it doesn't check subfolders. So when you want to include
  137. a file from this subfolder, you must specify the subfolder as well.
  138. Hence, the line `#include <SDL2/SDL_timer.h` really results in the compiler including the content
  139. from /usr/include/SDL2/SDL_timer.h.
  140. By the way, you can also choose to include SDL2/SDL.h instead, which in turns includes all the
  141. other files. It's just a little convenience to make things easier for the programmer. With this
  142. approach you'll include a lot of definitions you don't need, but the references that aren't used
  143. are lost when the compiler turns the code into Assembly, so the only real consequence is that it
  144. takes every so slightly longer to build - a consequence no one really cares about.
  145. Section V: linking to SDL2
  146. --------------------------
  147. Trying to compile the code you added will result in a linker error:
  148. ----------------------------------- [ gcc output ] ---
  149. [cuterald $] gcc main.c
  150. /usr/bin/ld: /tmp/ccWVVpwe.o: in function `main':
  151. main.c:(.text+0x15): undefined reference to `SDL_Delay'
  152. collect2: error: ld returned 1 exit status
  153. -------------------------------------------------------
  154. This is because the actual implementation for SDL_Delay isn't in your program, and it's not in the
  155. C standard library either. You'll have to tell the compiler where to actually find it.
  156. Like with includes, GCC has a couple default places where it'll check for any library you may be
  157. trying to link to. So all you really have to do is pass it the name, and if SDL2 is installed
  158. properly, it will find it automatically.
  159. Compile it with this:
  160. --------- [ gcc command ] ---
  161. gcc -lSDL2 main.c -o cuterald
  162. -----------------------------
  163. This time the program will compile without errors. This is all you really need to know to compile
  164. any SDL2 program from now on, but as usual we'll go just a bit deeper so you can get a full
  165. understanding.
  166. GCC comes with a utility to check what an executable is linked to, called 'ldd'. Run it on any
  167. executable file, and it'll tell you exactly what it's linked to.
  168. For example:
  169. -------------------------------------------------------------------- [ ldd output ] ---
  170. [cuterald $] ldd cuterald
  171. linux-vdso.so.1 (0x00007fff87dd2000)
  172. libSDL2-2.0.so.0 => /usr/lib/libSDL2-2.0.so.0 (0x00007fa9dcbd8000)
  173. libc.so.6 => /usr/lib/libc.so.6 (0x00007fa9dca0f000)
  174. libm.so.6 => /usr/lib/libm.so.6 (0x00007fa9dc8c9000)
  175. libdl.so.2 => /usr/lib/libdl.so.2 (0x00007fa9dc8c3000)
  176. libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fa9dc8a1000)
  177. /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fa9dcdb4000)
  178. ---------------------------------------------------------------------------------------
  179. This shows you that gcc links to a couple standard libraries by default (which is why you can use
  180. printf and other default functions without having to manually link), and SDL is in there as well.
  181. From this output, you can learn that the SDL2 implementation really sits in
  182. /usr/lib/libSDL2-2.0.so.0
  183. That's a .o file - the result of the assembly stage in GCC, and the binary format that gets used as
  184. input for the linker stage. When you pass the -l flag for GCC, this file is the one that is used
  185. during linking to find the implementation for any SDL2 function.
  186. Section VI: chapter summary
  187. ---------------------------
  188. Your program doesn't really do anything yet. It just waits the amount of milliseconds that you
  189. passed to SDL_Delay, and then quits. The important part is that it runs at all - using and linking
  190. to external libraries is one of those things that have a steep learning cure, but are very easy
  191. once you understand how it works.
  192. In summary, this is what we learned today (and the last chapter):
  193. * SDL2 provides a number of features to make game development easy
  194. * Like most libraries, you need to #include the necessary files, and also link to the actual binary
  195. library file.
  196. * Includes are usually in /usr/include/ and subfolders.
  197. * Library files are usually in /usr/lib
  198. * Any library can be linked to using the -l flag.
  199. * Failing to provide the library name will result in a linker error.
  200. * SDL2 has documentation online at https://wiki.libsdl.org/, as well as in the Linux man pages.
  201. * SDL_Delay waits a given amount of milliseconds, then returns.
  202. * ldd can show you what libraries a binary is linked to.
  203. Don't forget to git add and commit your code!