安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

CMake库搜索函数居然不搜索LDLIBRARYPATH

4月28日 天浪楼投稿
  摘要:本文通过编译后运行找不到库文件的问题引入,首先分析了findpackage(JNI)的工作流程,而后针对cmake不搜索LDLIBRARYPATH的问题,提出了一种通用的解决办法。
  本文分享自华为云社区《CMake库搜索函数居然不搜索LDLIBRARYPATH?由编译工具使用体验而引发的思考云社区华为云》,作者:蜉蝣与海。
  最近产品要使用JNI技术,CMake编译C代码时需要对外链接libjvm。so库。代码编译倒是正常,系统中也有libjvm。so,然而使用时却报了如下异常:errorwhileloadingsharedlibraries:libjvm。so:cannotopensharedobjectfile:Nosuchfileordirectory
  这个报错表示,操作系统并没有找到libjvm。so,我们的操作系统是从LDLIBRARYPATH中搜索这些动态链接库,很显然目前libjvm。so并不在这个目录下。
  问题的解决倒是简单,直接在LDLIBRARYPATH里加入libjvm。so的库即可。但是这却引发了我的思考:为什么构建时可以找到libjvm。so,运行时却找不到呢?
  这个问题的回答,既可以有简明扼要版解释,又可以刨根问底深挖。
  先来看简明扼要版解释:
  代码的CMakeList中使用了下列语句,在编译过程中寻找并链接libjvm。so,这个搜索方式和操作系统的搜索方式不同:findpackage(JNI)getfilenamecomponent(JVMLIBPATH{JAVAJVMLIBRARY}DIRECTORY)getfilenamecomponent(JAVALIBPATH{JVMLIBPATH}DIRECTORY)linkdirectories({JVMLIBPATH}{JAVALIBPATH})settargetproperties({NAME}PROPERTIESLINKFLAGSljvm)
  其中findpackage(JNI)会搜索libjvm。so可能存在的路径,通过getfilenamecomponent来获得libjvm。so的文件夹,并把这个文件夹设为默认搜索库路径。而后settargetproperties会进行链接工作。
  这个答案只能告诉我们是什么,但是作为一只程序猿,还要了解为什么,这里引申几个问题讨论:1、findpackage(JNI)的工作过程是怎样的?为什么LDLIBRARYPATH里没找到的依赖库,cmake可以找到2、cmake的库搜索函数findlibrary会搜索LDLIBRARYPATH吗,如果不会,可以通过设置来搜索LDLIBRARYPATH吗?问题一:findpackage(JNI)的工作过程是怎样的
  为了方便开发者引用外部包,cmake官方预定义了许多寻找依赖包的Module,他们存储在cmake的sharecmakeModules目录下。每个以Find。cmake命名的文件都可以帮我们找到一个包〔1〕。在本地计算机执行以下指令,即可找到findpackage(JNI)使用的脚本文件。findnameFindJNI。cmake
  打开自己的cmake对应的FindJNI文件,可以看到密密麻麻的注释和脚本,通过阅读这些脚本,我们得以得知FindJNI是如何工作的。
  分析问题前,先看问题带来的结果,文件最上方注释有如下说明:Thismodulesetsthefollowingresultvariables:JNIINCLUDEDIRStheincludedirstouseJNILIBRARIESthelibrariestouse(JAWTandJVM)JNIFOUNDTRUEifJNIheadersandlibrarieswerefound。CacheVariablesThefollowingcachevariablesarealsoavailabletosetoruse:JAVAAWTLIBRARYthepathtotheJavaAWTNativeInterface(JAWT)libraryJAVAJVMLIBRARYthepathtotheJavaVirtualMachine(JVM)libraryJAVAINCLUDEPATHtheincludepathtojni。hJAVAINCLUDEPATH2theincludepathtojnimd。handjniport。hJAVAAWTINCLUDEPATHtheincludepathtojawt。h
  这段代码表明,执行findpackage(JNI)之后,会有一系列变量被设置,其中包括表示JNI是否被找到的变量JNIFOUND,以及表示libjvm。so的变量JAVAJVMLIBRARY。这些变量在设定之后,通过FindPackageHandleStandardArgs导出,返回调用处,FindPackageHandleStandardArgs是cmake专门用来导出变量的宏〔2〕:include({CMAKECURRENTLISTDIR}FindPackageHandleStandardArgs。cmake)FINDPACKAGEHANDLESTANDARDARGS(JNIDEFAULTMSGJAVAAWTLIBRARYJAVAJVMLIBRARYJAVAINCLUDEPATHJAVAINCLUDEPATH2JAVAAWTINCLUDEPATH)
  在文件中定位JAVAJVMLIBRARY,可以追踪到下述代码片段:foreach(search{JNISEARCHES})findlibrary(JAVAJVMLIBRARY{JNI{search}JVM})findlibrary(JAVAAWTLIBRARY{JNI{search}JAWT})if(JAVAJVMLIBRARY)break()endif()endforeach()
  由此可知,JAVAJVMLIBRARY这个变量,是通过逐个搜索{JNI{search}JVM}里的文件夹进而确定JAVAJVMLIBRARY的。而{JNI{search}JVM}相关的定义语句如图:set(JNIFRAMEWORKJVMNAMESJavaVM)set(JNINORMALJVMNAMESjvmPATHS{JAVAJVMLIBRARYDIRECTORIES})
  其中JAVAJVMLIBRARYDIRECTORIES中涉及了大量可能的libjvm。so存在的路径。set(JAVAJVMLIBRARYDIRECTORIES)foreach(dir{JAVAAWTLIBRARYDIRECTORIES})list(APPENDJAVAJVMLIBRARYDIRECTORIES{dir}{dir}client{dir}serverIBMSDK,JavaTechnologyEdition,specificpaths{dir}j9vm{dir}default)endforeach()set(JAVAAWTLIBRARYDIRECTORIES)if(JAVAHOME)JAVAAPPENDLIBRARYDIRECTORIES(JAVAAWTLIBRARYDIRECTORIES{JAVAHOME}jrelib{libarch}{JAVAHOME}jrelib{JAVAHOME}lib{libarch}{JAVAHOME}lib{JAVAHOME})endif()JAVAAPPENDLIBRARYDIRECTORIES(JAVAAWTLIBRARYDIRECTORIES{JNIJAVAAWTLIBRARYTRIES})foreach(javadirINLISTSJNIJAVADIRECTORIESBASE)list(APPENDJNIJAVAAWTLIBRARYTRIES{javadir}jrelib{libarch}{javadir}jrelib{javadir}lib{libarch}{javadir}lib{javadir})list(APPENDJNIJAVAINCLUDETRIES{javadir}include)endforeach()
  如上图所示,变量依赖顺序如下:
  JAVAJVMLIBRARYDIRECTORIESJAVAAWTLIBRARYDIRECTORIESJNIJAVAAWTLIBRARYTRIESJAVAHOMEJNIJAVADIRECTORIESBASE
  最终发现JAVAJVMLIBRARYDIRECTORIES变量的值,是由JAVAHOME变量的值和JNIJAVADIRECTORIESBASE变量的值共同决定的。而JNIJAVADIRECTORYBASE预置了大量预定义路径:set(JNIJAVADIRECTORIESBASEusrlibjvmjavausrlibjavausrlibjvmusrlocallibjavausrlocalsharejavausrlibj2sdk1。4sunusrlibj2sdk1。5sunoptsunjdk1。5。0。04usrlibjvmjava6sunusrlibjvmjava1。5。0sunusrlibjvmjava6sun1。6。0。00canthisoneberemovedaccordingto8821?Alexusrlibjvmjava6openjdkusrlibjvmjava1。6。0openjdk1。6。0。0fedoraDebianspecificpathsfordefaultJVMusrlibjvmdefaultjavaArchLinuxspecificpathsfordefaultJVMusrlibjvmdefaultUbuntuspecificpathsfordefaultJVMusrlibjvmjava11openjdk{libarch}Ubuntu18。04LTSusrlibjvmjava8openjdk{libarch}Ubuntu15。10usrlibjvmjava7openjdk{libarch}Ubuntu15。10usrlibjvmjava6openjdk{libarch}Ubuntu15。10OpenBSDspecificpathsfordefaultJVMusrlocaljdk1。7。0usrlocaljre1。7。0usrlocaljdk1。6。0usrlocaljre1。6。0SuSEspecificpathsfordefaultJVMusrlib64jvmjavausrlib64jvmjre)
  通过以上分析可以看出,JAVAJVMLIBRARY的搜索,依赖JAVAHOME和大量预定义路径。问题二:cmake库搜索函数findlibrary会搜索LDLIBRARYPATH吗
  通过阅读DoesCMakesfindlibrarysearchLDLIBRARYPATH可以知道,findlibrary默认不搜索LDLIBRARYPATH,并且网上也找不到让cmake搜索LDLIBRARYPATH的文章。那cmake能搜索LDLIBRARYPATH吗?
  答案是可以的,通过cmake获取LDLIBRARYPATH环境变量,并转为cmake可理解的list格式,而后注入findlibrary即可,代码如下:string(REPLACE:;RUNTIMEPATHENV{LDLIBRARYPATH})findlibrary(JVMAPINAMESjvmHINTS{RUNTIMEPATH})if(JVMAPISTREQUALJVMAPINOTFOUND)message(WARNINGfoundlibjvm。soonlyin{JAVAJVMLIBRARY}butnotinLDLIBRARYPATH。environmentvariableLDLIBRARYPATHmustincludeitsdirectory。)endif()
  如果希望找不到这个库时编译失败,可以将WARNING改为fatalerror,代码如下:string(REPLACE:;RUNTIMEPATHENV{LDLIBRARYPATH})findlibrary(JVMAPINAMESjvmHINTS{RUNTIMEPATH})if(JVMAPISTREQUALJVMAPINOTFOUND)message(FATALERRORfoundlibjvm。soonlyin{JAVAJVMLIBRARY}butnotinLDLIBRARYPATH。environmentvariableLDLIBRARYPATHmustincludeitsdirectory。)endif()小结
  本文通过编译后运行找不到库文件的问题引入,首先分析了findpackage(JNI)的工作流程,而后针对cmake不搜索LDLIBRARYPATH的问题,提出了一种通用的解决办法。参考文献:
  〔1〕Cmake之深入理解findpackage()的用法:https:zhuanlan。zhihu。comp97369704?utmsourcewechatsession
  〔2〕Cmake中findpackage命令的搜索模式之模块模式(Modulemode):https:www。jianshu。compf983a90bcf91
  〔3〕DoesCMakesfindlibrarysearchLDLIBRARYPATH?:https:stackoverflow。comquestions41566316doescmakesfindlibrarysearchldlibrarypath
  点击下方,第一时间了解华为云新鲜技术
  华为云博客大数据博客AI博客云计算博客开发者中心华为云
投诉 评论 转载

三伏天补脾正当时,建议40岁后这4种食物每天吃点,别心疼钱了进入三伏天后,天气是越来越热,而且一天比一天闷热,内外湿度大,这个季节偏偏人又容易疲累,搞得不知道要怎么办才好。其实,脾胃好了,身体才会轻松。今天我就给大家推荐4种三伏天……顺丰饿了么爱奇艺小红书30多家企业用户协议藏霸王条款用户协议里指定消费争议管辖法院的条款是什么意思?你要是随手勾选同意协议,一旦发生纠纷就得跑到异地去打官司。近日,《中国消费者报》记者调查、梳理了30多家企业的用户协议以及……读途考察7被葡萄掩盖了光芒的吐鲁番(二)很多年前,我第一次看《指环王》。电影最后,在人类王国刚铎首都米那斯提力斯,阿拉贡从埃尔隆德手中接过了安努米那斯权杖。他和精灵阿尔温在仲夏节那天举行了婚礼。镜头从米那斯提力……罕见暴跌,两天股价跌七成!这只股怎么了?红衣大炮基本不碰用户隔夜美股巨震,10日上午,A股跳空低开,截至上午收盘,上证指数下跌0。53,深证成指下跌1。42,创业板指下跌1。81,北向资金净流出21。01亿元。盘面上,Web3。0……一棵老槐树,见证了一个村庄的百年历史文段绪军我们东段庄村曾有一棵巨大的老槐树。小时候跟着伙伴们到村中遛弯,常常被老槐树那高耸入云的身躯所震撼。老槐树身粗,要五六个人牵起手才能环抱过来。可那时走向暮年的老槐树……央企诞生巨无霸,年利润高达上千亿,将引领世界能源新格局?中国电网一个低调且不出名的世界五百强,年利润高达上千亿,华为,腾讯,阿里其面前也只能是一个弟弟般的存在。掌控世界最强大的发电技术,引领世界能源的新格局,让老美头疼不已,一……研究人员利用DNA测试对海洋微生物进行革命性的全面区域诊断加州大学圣地亚哥分校斯克里普斯海洋研究所、J。CraigVenter研究所(JCVI)和美国国家海洋和大气管理局(NOAA)的科学家们使用类似于家谱研究中使用的遗传学研究工具来……癫痫预防要注意哪些方面一直以来在临床方面癫痫病的预防一直倍受医生和患者的关注,能够及时科学地进行癫痫病的预防,不仅可以对已患癫痫者的发作有阻止或减少的作用,另外还可以促进患者的康复,能够帮助大家大大……ampampquot精明ampampquot李冰冰强吻陈坤和朱孝天在酒店走廊对李冰冰一顿乱嘬嘬走了演艺圈最纯洁的欲女2004年朱孝天从房间百米冲刺到大厅而后一头扎进李冰冰怀抱两人激情四射在酒店走廊目无旁人亲热……普京签署部分动员令,乌克兰总统办公室顾问回应来源:环球网【环球网报道】根据克里姆林宫网站21日发布的消息,俄罗斯总统普京签署了部分动员令。据路透社21日最新报道,乌克兰总统办公室顾问波多利亚克当天对此回应称,俄罗斯……34万元的正装腕表,通勤首选〔腕表之家表款推荐〕除了一些特殊行业,比如说银行、体制内、销售等等,其实现在的公司对员工的穿搭大部分都比较宽松,所以穿日常便服还是比较多的,但是也不排除一些正式场合需要穿着正装……CMake库搜索函数居然不搜索LDLIBRARYPATH摘要:本文通过编译后运行找不到库文件的问题引入,首先分析了findpackage(JNI)的工作流程,而后针对cmake不搜索LDLIBRARYPATH的问题,提出了一种通用的……
中超2022年亚冠4队出炉!中超升班马创奇迹时隔12年回归亚谁是世界杯的奇兵?国内想要使用TikTok?这些你必须得掌握给小白演示分库分表案例每日美图文案第十二期CBA战神刘玉栋退役后曾任八一队领队,如今重新出发身居要职孙俪美到国外去了,白色洞洞装也穿出高级感,真优雅到骨子里秋果之王正上市,每天吃几个,腰好肾好腿脚灵活!别错过安徽石台皖南小众旅游地!自驾天路发现地道美味建筑模拟器万丈高楼平地起,高楼遥遥远眺,远处建筑鳞次栉比6人狂轰113分,山西集体大暴走!张宁225兑现天赋,他该进低价才是王道!国产旗舰销量反超苹果手机,价格是苹果手机的一半民法总则的正当防卫是指什么陈情令金子轩为什么退婚金子轩喜欢江厌离吗军训三部曲作文西单最新小网红,10元吃撑调岗通知书扬州市美术馆游玩攻略爱唠叨的妈妈中班美术教案老人应该怎么安排早餐好物分享奶奶用一个笨办法,把2岁的孙女培养成了小学霸张一鸣再发声美国真正目的是全面封禁也曾走过弯路,但幸而复色!

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利