{"id":109818,"date":"2024-05-29T07:00:00","date_gmt":"2024-05-29T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109818"},"modified":"2024-06-02T07:44:10","modified_gmt":"2024-06-02T14:44:10","slug":"20240529-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240529-00\/?p=109818","title":{"rendered":"A graphical depiction of the steps in building a C++ executable, basics"},"content":{"rendered":"<p>One of the things you have to know when trying to diagnose a build failure is understanding what each step of the build accomplishes, so that you can fix the problem at the correct step.<\/p>\n<p>Here&#8217;s the basic idea.<\/p>\n<div id=\"p20240529_head\" style=\"display: none;\">\u00a0<\/div>\n<div id=\"p20240529_defs\" style=\"height: 0;\">\u00a0<\/div>\n<table style=\"text-align: center; border-collapse: separate; line-height: 1;\" title=\"Described in text.\" border=\"0\" cellspacing=\"1\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td style=\"width: 6em;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 6em; border: solid 1px currentcolor; padding: 1ex;\">.h, .cpp<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">C++ compiler<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.obj<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_swarr\">\u2199<\/td>\n<td id=\"p20240529_darr5\" rowspan=\"5\">\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">librarian<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.lib<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_searr\">\u2198<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">linker<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.dll, .exe<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Given a bunch of header files (.h) and C++ source files (.cpp), the C++ compiler produces a corresponding set of object files (.obj).\u00b9 If your project builds a library, then the object files are given to the librarian to produce a library file, and that&#8217;s your project. In other words, your library project uses only the top part of the diagram, through to building the .lib file, but doesn&#8217;t go down the other branch that leads to the linker.<\/p>\n<table style=\"text-align: center; border-collapse: separate; line-height: 1;\" title=\"Described in text.\" border=\"0\" cellspacing=\"1\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td style=\"width: 6em;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 6em; border: solid 1px currentcolor; padding: 1ex;\">.h, .cpp<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">C++ compiler<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.obj<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_swarr\">\u2199<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">librarian<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.lib<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If your project builds an executable module (a .dll or .exe, for example), then the object files and any input libraries are given to the linker, which then generates the desired module file. In that case, you&#8217;re using the other branch of the diagram that leads to the linker:<\/p>\n<table style=\"text-align: center; border-collapse: separate; line-height: 1;\" title=\"Described in text.\" border=\"0\" cellspacing=\"1\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td style=\"width: 6em;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 6em; border: solid 1px currentcolor; padding: 1ex;\">.h, .cpp<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">C++ compiler<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.obj<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr5\" rowspan=\"5\">\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<br \/>\n\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.lib<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_searr\">\u2198<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; border-radius: 3ex; padding: 1ex;\">linker<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td id=\"p20240529_darr\">\u2193<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; padding: 1ex;\">.dll, .exe<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Already you know enough to solve this problem:<\/p>\n<blockquote class=\"q\"><p>My solution <a title=\"Avoiding the redundancy of adding the object files to both the primary project and its unit test\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230222-00\/?p=107864\"> consists of three projects<\/a>: A core library, a program that consumes the library, and a unit test that consumes that same library. I added some code to the core library, and now the program and unit test are generating linker errors due to a missing import library used by the code I added. I added that library to the core library&#8217;s <tt>Additional\u00adDependencies<\/tt>, but that didn&#8217;t fix it.<\/p><\/blockquote>\n<p>Next time, we&#8217;ll expand this diagram to include additional tools you may encounter in Windows projects.<\/p>\n<p><b>Answer to exercise<\/b>: The error complaining about the unresolved external symbol is coming from the linker, so you need to provide the library with that symbol to the linker. The core library project doesn&#8217;t run the linker: It runs the librarian to produce <tt>corelibrary.lib<\/tt>. It&#8217;s the program and unit test that consume the <tt>corelibrary.lib<\/tt> and produce <tt>contoso.exe<\/tt> and <tt>contoso_unittest.exe<\/tt>, respectively. Those are the projects that need the new library listed in the <tt>Additional\u00adDependencies<\/tt>.<\/p>\n<p>To avoid having to update both the program and unit test each time the build requirements of the core library change, you might put those special configuration settings in a separate file that is included by the program and unit test projects, so that any changes need to be made in only one place.<\/p>\n<p>\u00b9 For unix, the same principles apply, but the file extensions are different. The extension for object files is .o, the extensions for library files are .a and .so, depending on what type of library they are. And unix executables traditionally have no extension.<\/p>\n<p>\n<script>\nwindow.addEventListener(\"load\", function() {\n  var fullFF = getComputedStyle(document.body).fontFamily;\n  var simpleFF = fullFF.replace(\/ Emoji\/g, \"\");\n  \/\/ break up \"style\" to prevent wordpress from injecting random junk\n  document.getElementById(\"p20240529_head\").innerHTML =\n`<s` + `tyle>\nbody { font-family: ${simpleFF}; }\n.emoji { font-family: ${fullFF}; }\n.entry-content th { padding: 1px; } \/* stylesheet workaround *\/\n.entry-content td { padding: 1px; } \/* stylesheet workaround *\/\n<\/s` + `tyle>`;\n}); \/\/ wacky comment to prevent wordpress from injecting random junk\n(function() {\n  var svg = {\n    defs: `<svg width=\"0\" height=\"0\">\n <defs>\n  <marker id=\"arrowhead\" markerWidth=\"5\" markerHeight=\"5\" refX=\"-2\" refY=\"0\"\n    viewBox=\"-6 -6 12 12\" orient=\"auto\">\n    <polygon points=\"-2,0 -5,5 5,0 -5,-5\" fill=\"currentcolor\" stroke=\"currentcolor\"\n      stroke-dasharray=\"1 0\" \/>\n  <\/marker>\n  <path id=\"darr\" d=\"M10,3 L10,15\" stroke=\"currentcolor\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"darr5\" d=\"M10,3 L10,125\" stroke=\"currentcolor\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"searr\" d=\"M3,3 L15,15\" stroke=\"currentcolor\"\n   marker-end=\"url(#arrowhead)\" \/>\n  <path id=\"swarr\" d=\"M20,2 L3,15\" stroke=\"currentcolor\"\n   marker-end=\"url(#arrowhead)\" \/>\n <\/defs>\n<\/svg>`,\n    darr: `<svg width=\"20\" height=\"20\"><use href=\"#darr\"\/><\/svg>`,\n    darr5: `<svg width=\"20\" height=\"130\"><use href=\"#darr5\"\/><\/svg>`,\n    searr: `<svg width=\"20\" height=\"20\"><use href=\"#searr\"\/><\/svg>`,\n    swarr: `<svg width=\"20\" height=\"20\"><use href=\"#swarr\"\/><\/svg>`\n  };\n  Object.keys(svg).forEach(function (key) {\n    Array.prototype.forEach.call(document.querySelectorAll(\"#p20240529_\" + key),\n      function (e) {\n        e.innerHTML = svg[key];\n      });\n  });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A high-level overview.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-109818","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A high-level overview.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109818","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109818"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109818\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109818"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109818"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109818"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}