{"thread":{"id":"35567","subject":"Rationale behind 'extern' on protypes in .h files","startedAt":"2013-12-22T15:51:30Z","lastAt":"2013-12-23T16:59:25Z","messageCount":5,"participants":["Ravi Shekhar Jethani","Stefan Beller","Jed Brown"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"232353","messageId":"CAKTJ_1zecXP03k_2YRnm_26n=anxkG6=k+isZxnnjWgfec70LA@mail.gmail.com","threadId":"35567","inReplyTo":null,"subject":"Rationale behind 'extern' on protypes in .h files","fromName":"Ravi Shekhar Jethani","fromEmail":"rsjethani@gmail.com","sentAt":"2013-12-22T15:51:30Z","receivedAt":"2013-12-22T15:51:30Z","isPatch":false,"sender":{"key":"rsjethani@gmail.com","avatar":null},"body":"Hi,\nI am a C & Data Structure teacher at at an institute. Up until now I\nhave only written classroom type C code. I always had interest in\noperating systems especially Linux Kernel but never got into anything\njust passively followed 'lwn.net', 'dr dobbs magazine' etc.\n\nBut the series '30 Linux Kernel Developers in 30 Weeks' on 'linux.com'\nhas really pushed me over the edge and  I have this new found interest\ntowards Linux and C. As these articles suggest that I should have a\ngood experience in user space before I can even touch the kernel. So\nto get a feel of how actual real world C projects look like I have\ntaken two excellent projects as my reference 'Git' and 'libvirt'. Also\n'Linux Formrnal Scratch' to get started towards Linux internals.\n\nAlthough I have a good understanding of the basic/advanced concepts\nlike pointers, memory management etc but many concepts like good error\nhandling mechanism, unit testing, build systems etc. were always\nblurry but I know that this is just a start towards a long journey\ntowards Linux Kernel.\n\n\nNow, my real question :\n1) I cannot understand the reason behind making function prototypes as\nextern. What purpose does this serve? AFAIK we put definition in a .c\nfile and the prototype in a .h thats it.\n\n2) Why are some  prototypes in some of the .h file are extern and\nothers are not?\n\nThank you guys for reading through. Any suggestions are humbly welcome.\nRavi S. Jethani\n"},{"id":"232354","messageId":"52B71D24.4000207@googlemail.com","threadId":"35567","inReplyTo":"CAKTJ_1zecXP03k_2YRnm_26n=anxkG6=k+isZxnnjWgfec70LA@mail.gmail.com","subject":"Re: Rationale behind 'extern' on protypes in .h files","fromName":"Stefan Beller","fromEmail":"stefanbeller@googlemail.com","sentAt":"2013-12-22T17:11:00Z","receivedAt":"2013-12-22T17:11:00Z","isPatch":false,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On 22.12.2013 16:51, Ravi Shekhar Jethani wrote:\n\n> \n> Now, my real question :\n> 1) I cannot understand the reason behind making function prototypes as\n> extern. What purpose does this serve? AFAIK we put definition in a .c\n> file and the prototype in a .h thats it.\n> \n> 2) Why are some  prototypes in some of the .h file are extern and\n> others are not?\n> \n> Thank you guys for reading through. Any suggestions are humbly welcome.\n> Ravi S. Jethani\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n\nThat's an interesting question. From my understanding there is no\ndifference for functions declarations being set to extern or not,\nbecause extern is the default on functions. It is however important\nfor variables to mark them extern if they're in a header file.\n\nAfter a quick research on the web, it may be there for historical\nreasons. Back then, when there were one pass compilers,\nthe compiler needed to know where the function is to be found.\n(extern was not default at these times?)\n\nAnother reason I could make up, would be to indicate,\nwhether the function is in the c file having the\nsame name as the header file.\nFor example in builtin.h there are all the functions declared\nextern, as the implementation of the functions are found in\nbuiltin/*.c\nIn another header cache-tree.h there are function declarations\nwithout explicit extern keyword, and the implementation\nis found in the cache-tree.c file (${SAME-NAME-AS-HEADER}.C)\nThis is however not always the case as found in archive.{c,h}\n\nI'd be also interested in knowing the real reason for this rationale.\n\nThanks,\nStefan\n"},{"id":"232355","messageId":"87eh54spw3.fsf@jedbrown.org","threadId":"35567","inReplyTo":"52B71D24.4000207@googlemail.com","subject":"Re: Rationale behind 'extern' on protypes in .h files","fromName":"Jed Brown","fromEmail":"jed@59a2.org","sentAt":"2013-12-22T18:26:52Z","receivedAt":"2013-12-22T18:26:52Z","isPatch":false,"sender":{"key":"jed@59a2.org","avatar":"https://gravatar.com/avatar/1391d04d82555f9058a9fdf5eead233e909a48e40480db31fc554e7afeb301da?d=mp&s=160"},"body":"Stefan Beller <stefanbeller@googlemail.com> writes:\n> From my understanding there is no\n> difference for functions declarations being set to extern or not,\n> because extern is the default on functions.\n\nThere is a difference for shared libraries if you would like to control\nwhich symbols are exported.  With gcc, for example, you might compile\nusing -fvisibility=hidden.  Any functions explicitly declared with\nextern, bearing __attribute__((visibility(\"default\")), or using\nvisibility pragmas will be exported (similar to __declspec(dllexport) on\nWindows).  Other functions will be internal to the shared library so you\ndon't have to worry about callers depending on those symbols and\nperformance can be a bit better by skipping the PLT and avoiding symbol\nrelocations at load time.  See Drepper's guide for more.\n\nhttp://www.akkadia.org/drepper/dsohowto.pdf\n"},{"id":"232361","messageId":"CAKTJ_1z-pMePmh4phM2TXSMx0kOjGJ0afQ_JRESggi=k6+y-jA@mail.gmail.com","threadId":"35567","inReplyTo":"87eh54spw3.fsf@jedbrown.org","subject":"Re: Rationale behind 'extern' on protypes in .h files","fromName":"Ravi Shekhar Jethani","fromEmail":"rsjethani@gmail.com","sentAt":"2013-12-23T15:24:09Z","receivedAt":"2013-12-23T15:24:09Z","isPatch":false,"sender":{"key":"rsjethani@gmail.com","avatar":null},"body":"2013/12/22 Jed Brown <jed@59a2.org>:\n> There is a difference for shared libraries if you would like to control\n> which symbols are exported.  With gcc, for example, you might compile\n> using -fvisibility=hidden.  Any functions explicitly declared with\n> extern, bearing __attribute__((visibility(\"default\")), or using\n> visibility pragmas will be exported (similar to __declspec(dllexport) on\n> Windows).  Other functions will be internal to the shared library so you\n> don't have to worry about callers depending on those symbols and\n> performance can be a bit better by skipping the PLT and avoiding symbol\n> relocations at load time.  See Drepper's guide for more.\n>\n> http://www.akkadia.org/drepper/dsohowto.pdf\n\nTo check this I installed the libgit2-dev package which installed:\n/usr/include/git2/*.h , /usr/lib/libgit2.so\nNow, I exported all symbols using:\n$ readelf -s /usr/lib/libgit2.so\nand tried to match these with 'externed' prototypes in the Git source\ndirectory..no matches.\nI am confused!!!.\n\nAlso I checked this:\n$ ldd git\nThere is no 'gitish' .so in the output; it seems everything is packed\ninside one executable.\nSo your second point 'skipping the PLT...' also doesn't seem to apply here.\n\n\nRegards,\nRavi Shekhar Jethani\n"},{"id":"232362","messageId":"87fvpjqz9u.fsf@jedbrown.org","threadId":"35567","inReplyTo":"CAKTJ_1z-pMePmh4phM2TXSMx0kOjGJ0afQ_JRESggi=k6+y-jA@mail.gmail.com","subject":"Re: Rationale behind 'extern' on protypes in .h files","fromName":"Jed Brown","fromEmail":"jed@59a2.org","sentAt":"2013-12-23T16:59:25Z","receivedAt":"2013-12-23T16:59:25Z","isPatch":false,"sender":{"key":"jed@59a2.org","avatar":"https://gravatar.com/avatar/1391d04d82555f9058a9fdf5eead233e909a48e40480db31fc554e7afeb301da?d=mp&s=160"},"body":"Ravi Shekhar Jethani <rsjethani@gmail.com> writes:\n> To check this I installed the libgit2-dev package which installed:\n> /usr/include/git2/*.h , /usr/lib/libgit2.so\n> Now, I exported all symbols using:\n> $ readelf -s /usr/lib/libgit2.so\n> and tried to match these with 'externed' prototypes in the Git source\n> directory..no matches.\n> I am confused!!!.\n\nlibgit2 is an entirely different package from Git.  If you look at the\nlibgit2 sources (https://github.com/libgit2/libgit2), look in\ninclude/git2/common.h:\n\n/** Declare a public function exported for application use. */\n#if __GNUC__ >= 4\n# define GIT_EXTERN(type) extern \\\n                         __attribute__((visibility(\"default\"))) \\\n                         type\n#elif defined(_MSC_VER)\n# define GIT_EXTERN(type) __declspec(dllexport) type\n#else\n# define GIT_EXTERN(type) extern type\n#endif\n\n\nI have always used __attribute__((visibility(\"default\"))), but the gcc\nman page says\n\n    extern declarations are not affected by -fvisibility, so a lot of\n    code can be recompiled with -fvisibility=hidden with no\n    modifications.  However, this means that calls to \"extern\" functions\n    with no explicit visibility use the PLT, so it is more effective to\n    use \"__attribute ((visibility))\" and/or \"#pragma GCC visibility\" to\n    tell the compiler which \"extern\" declarations should be treated as\n    hidden.\n\nHowever, I don't understand what the first statement means\n(documentation bug?) since -fvisibility=hidden causes functions declared\nwith 'extern' to be hidden.\n\nsymbols.c:\nEXTERN int foo(void);\nint foo(void) {return 1;}\n\n$ gcc -fvisibility=hidden -DEXTERN=extern -shared -o libsymbols.so symbols.c\n$ nm -D libsymbols.so | grep foo\n$\n\nmeanwhile,\n\n$ gcc -fvisibility=hidden -DEXTERN='__attribute((visibility(\"default\")))' -shared -o libsymbols.so symbols.c\n$ nm -D libsymbols.so | grep foo\n000000000000055c T foo\n\n> Also I checked this:\n> $ ldd git\n> There is no 'gitish' .so in the output; it seems everything is packed\n> inside one executable.\n> So your second point 'skipping the PLT...' also doesn't seem to apply here.\n\nMy comment applied to shared libraries in general, not specifically to\nGit (which isn't a shared library).\n"}]}