| 889 | } |
| 890 | |
| 891 | void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements( |
| 892 | std::string const& config, std::vector<std::string> const& architectures, |
| 893 | std::string const& output) |
| 894 | { |
| 895 | // Ensure there are no duplicates. |
| 896 | cmNinjaDeps const explicitDeps = [&]() -> std::vector<std::string> { |
| 897 | std::unordered_set<std::string> depsSet; |
| 898 | cmNinjaDeps const linkDeps = |
| 899 | this->ComputeLinkDeps(this->TargetLinkLanguage(config), config, true); |
| 900 | cmNinjaDeps const objects = this->GetObjects(config); |
| 901 | depsSet.insert(linkDeps.begin(), linkDeps.end()); |
| 902 | depsSet.insert(objects.begin(), objects.end()); |
| 903 | |
| 904 | std::vector<std::string> deps; |
| 905 | std::copy(depsSet.begin(), depsSet.end(), std::back_inserter(deps)); |
| 906 | return deps; |
| 907 | }(); |
| 908 | |
| 909 | cmGlobalNinjaGenerator* globalGen{ this->GetGlobalGenerator() }; |
| 910 | std::string const objectDir = |
| 911 | cmStrCat(this->GeneratorTarget->GetSupportDirectory(), |
| 912 | globalGen->ConfigDirectory(config)); |
| 913 | std::string const ninjaOutputDir = this->ConvertToNinjaPath(objectDir); |
| 914 | |
| 915 | cmNinjaBuild fatbinary(this->LanguageLinkerCudaFatbinaryRule(config)); |
| 916 | |
| 917 | // Link device code for each architecture. |
| 918 | for (std::string const& architectureKind : architectures) { |
| 919 | // Clang always generates real code, so strip the specifier. |
| 920 | std::string const architecture = |
| 921 | architectureKind.substr(0, architectureKind.find('-')); |
| 922 | std::string const cubin = |
| 923 | cmStrCat(ninjaOutputDir, "/sm_", architecture, ".cubin"); |
| 924 | |
| 925 | cmNinjaBuild dlink(this->LanguageLinkerCudaDeviceRule(config)); |
| 926 | dlink.ExplicitDeps = explicitDeps; |
| 927 | dlink.Outputs = { cubin }; |
| 928 | dlink.Variables["ARCH"] = cmStrCat("sm_", architecture); |
| 929 | |
| 930 | // The generated register file contains macros that when expanded register |
| 931 | // the device routines. Because the routines are the same for all |
| 932 | // architectures the register file will be the same too. Thus generate it |
| 933 | // only on the first invocation to reduce overhead. |
| 934 | if (fatbinary.ExplicitDeps.empty()) { |
| 935 | dlink.Variables["REGISTER"] = cmStrCat( |
| 936 | "--register-link-binaries=", ninjaOutputDir, "/cmake_cuda_register.h"); |
| 937 | } |
| 938 | |
| 939 | fatbinary.Variables["PROFILES"] += |
| 940 | cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin); |
| 941 | fatbinary.ExplicitDeps.emplace_back(cubin); |
| 942 | |
| 943 | globalGen->WriteBuild(this->GetCommonFileStream(), dlink); |
| 944 | } |
| 945 | |
| 946 | // Combine all architectures into a single fatbinary. |
| 947 | fatbinary.Outputs = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") }; |
| 948 | globalGen->WriteBuild(this->GetCommonFileStream(), fatbinary); |
no test coverage detected