范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

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

  摘要: 本文通过编译后运行找不到库文件的问题引入,首先分析了find_package(JNI)的工作流程,而后针对cmake不搜索LD_LIBRARY_PATH的问题,提出了一种通用的解决办法。
  本文分享自华为云社区《CMake库搜索函数居然不搜索LD_LIBRARY_PATH? 由编译工具使用体验而引发的思考-云社区-华为云》,作者: 蜉蝣与海 。
  最近产品要使用JNI技术,CMake编译C++代码时需要对外链接libjvm.so库。代码编译倒是正常,系统中也有libjvm.so, 然而使用时却报了如下异常: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory
  这个报错表示,操作系统并没有找到libjvm.so, 我们的操作系统是从LD_LIBRARY_PATH中搜索这些动态链接库,很显然目前libjvm.so并不在这个目录下。
  问题的解决倒是简单,直接在LD_LIBRARY_PATH里加入libjvm.so的库即可。但是这却引发了我的思考: 为什么构建时可以找到libjvm.so, 运行时却找不到呢?
  这个问题的回答,既可以有简明扼要版解释,又可以刨根问底深挖。
  先来看简明扼要版解释:
  代码的CMakeList中使用了下列语句,在编译过程中寻找并链接libjvm.so,这个搜索方式和操作系统的搜索方式不同: find_package(JNI) get_filename_component(JVM_LIB_PATH ${JAVA_JVM_LIBRARY} DIRECTORY) get_filename_component(JAVA_LIB_PATH ${JVM_LIB_PATH} DIRECTORY) link_directories(${JVM_LIB_PATH} ${JAVA_LIB_PATH}) set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-ljvm")
  其中find_package(JNI)会搜索libjvm.so可能存在的路径,通过get_filename_component来获得libjvm.so的文件夹,并把这个文件夹设为默认搜索库路径。而后set_target_properties会进行链接工作。
  这个答案只能告诉我们"是什么",但是作为一只程序猿,还要了解"为什么",这里引申几个问题讨论: 1、find_package(JNI)的工作过程是怎样的?为什么LD_LIBRARY_PATH里没找到的依赖库,cmake可以找到 2、cmake的库搜索函数find_library会搜索LD_LIBRARY_PATH吗,如果不会,可以通过设置来搜索LD_LIBRARY_PATH吗? 问题一:find_package(JNI)的工作过程是怎样的
  为了方便开发者引用外部包,cmake官方预定义了许多寻找依赖包的Module, 他们存储在cmake的/share/-cmake-/Modules目录下。每个以Find.cmake命名的文件都可以帮我们找到一个包[1]。在本地计算机执行以下指令,即可找到find_package(JNI)使用的脚本文件。 find / -name FindJNI.cmake
  打开自己的cmake对应的FindJNI文件,可以看到密密麻麻的注释和脚本,通过阅读这些脚本,我们得以得知FindJNI是如何工作的。
  分析问题前,先看问题带来的结果,文件最上方注释有如下说明: This module sets the following result variables: ``JNI_INCLUDE_DIRS``  the include dirs to use ``JNI_LIBRARIES``   the libraries to use (JAWT and JVM) ``JNI_FOUND``   TRUE if JNI headers and libraries were found. Cache Variables ^^^^^^^^^^^^^^^ The following cache variables are also available to set or use: ``JAVA_AWT_LIBRARY``   the path to the Java AWT Native Interface (JAWT) library ``JAVA_JVM_LIBRARY``   the path to the Java Virtual Machine (JVM) library ``JAVA_INCLUDE_PATH``  the include path to jni.h ``JAVA_INCLUDE_PATH2``  the include path to jni_md.h and jniport.h ``JAVA_AWT_INCLUDE_PATH``  the include path to jawt.h
  这段代码表明,执行find_package(JNI)之后,会有一系列变量被设置,其中包括表示JNI是否被找到的变量JNI_FOUND,以及表示libjvm.so的变量JAVA_JVM_LIBRARY。这些变量在设定之后,通过FindPackageHandleStandardArgs导出,返回调用处,FindPackageHandleStandardArgs是cmake专门用来导出变量的宏[2]: include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(JNI  DEFAULT_MSG  JAVA_AWT_LIBRARY                                                     JAVA_JVM_LIBRARY                                                     JAVA_INCLUDE_PATH                                                     JAVA_INCLUDE_PATH2                                                     JAVA_AWT_INCLUDE_PATH)
  在文件中定位JAVA_JVM_LIBRARY, 可以追踪到下述代码片段: foreach(search ${_JNI_SEARCHES})  find_library(JAVA_JVM_LIBRARY ${_JNI_${search}_JVM})  find_library(JAVA_AWT_LIBRARY ${_JNI_${search}_JAWT})  if(JAVA_JVM_LIBRARY)  break()  endif() endforeach()
  由此可知,JAVA_JVM_LIBRARY这个变量,是通过逐个搜索${_JNI_${search}_JVM}里的文件夹进而确定JAVA_JVM_LIBRARY的。而${_JNI_${search}_JVM}相关的定义语句如图: set(_JNI_FRAMEWORK_JVM NAMES JavaVM) set(_JNI_NORMAL_JVM   NAMES jvm   PATHS ${JAVA_JVM_LIBRARY_DIRECTORIES}   )
  其中JAVA_JVM_LIBRARY_DIRECTORIES中涉及了大量可能的libjvm.so存在的路径。 set(JAVA_JVM_LIBRARY_DIRECTORIES) foreach(dir ${JAVA_AWT_LIBRARY_DIRECTORIES})  list(APPEND JAVA_JVM_LIBRARY_DIRECTORIES  "${dir}"  "${dir}/client"  "${dir}/server"  # IBM SDK, Java Technology Edition, specific paths  "${dir}/j9vm"  "${dir}/default"     ) endforeach() set(JAVA_AWT_LIBRARY_DIRECTORIES) if(_JAVA_HOME)   JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES  ${_JAVA_HOME}/jre/lib/{libarch}  ${_JAVA_HOME}/jre/lib  ${_JAVA_HOME}/lib/{libarch}  ${_JAVA_HOME}/lib  ${_JAVA_HOME}     ) endif() JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES  ${_JNI_JAVA_AWT_LIBRARY_TRIES}   ) foreach(_java_dir IN LISTS _JNI_JAVA_DIRECTORIES_BASE)  list(APPEND _JNI_JAVA_AWT_LIBRARY_TRIES  ${_java_dir}/jre/lib/{libarch}  ${_java_dir}/jre/lib  ${_java_dir}/lib/{libarch}  ${_java_dir}/lib  ${_java_dir}   )  list(APPEND _JNI_JAVA_INCLUDE_TRIES  ${_java_dir}/include   ) endforeach()
  如上图所示,变量依赖顺序如下:
  JAVA_JVM_LIBRARY_DIRECTORIES => JAVA_AWT_LIBRARY_DIRECTORIES => _JNI_JAVA_AWT_LIBRARY_TRIES & _JAVA_HOME => _JNI_JAVA_DIRECTORIES_BASE
  最终发现JAVA_JVM_LIBRARY_DIRECTORIES变量的值,是由JAVA_HOME变量的值和_JNI_JAVA_DIRECTORIES_BASE变量的值共同决定的。而JNI_JAVA_DIRECTORY_BASE预置了大量预定义路径: set(_JNI_JAVA_DIRECTORIES_BASE   /usr/lib/jvm/java   /usr/lib/java   /usr/lib/jvm   /usr/local/lib/java   /usr/local/share/java   /usr/lib/j2sdk1.4-sun   /usr/lib/j2sdk1.5-sun   /opt/sun-jdk-1.5.0.04   /usr/lib/jvm/java-6-sun   /usr/lib/jvm/java-1.5.0-sun   /usr/lib/jvm/java-6-sun-1.6.0.00       # can this one be removed according to #8821 ? Alex   /usr/lib/jvm/java-6-openjdk   /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0        # fedora  # Debian specific paths for default JVM   /usr/lib/jvm/default-java  # Arch Linux specific paths for default JVM   /usr/lib/jvm/default  # Ubuntu specific paths for default JVM   /usr/lib/jvm/java-11-openjdk-{libarch}    # Ubuntu 18.04 LTS   /usr/lib/jvm/java-8-openjdk-{libarch}    # Ubuntu 15.10   /usr/lib/jvm/java-7-openjdk-{libarch}    # Ubuntu 15.10   /usr/lib/jvm/java-6-openjdk-{libarch}    # Ubuntu 15.10  # OpenBSD specific paths for default JVM   /usr/local/jdk-1.7.0   /usr/local/jre-1.7.0   /usr/local/jdk-1.6.0   /usr/local/jre-1.6.0  # SuSE specific paths for default JVM   /usr/lib64/jvm/java   /usr/lib64/jvm/jre   )
  通过以上分析可以看出,JAVA_JVM_LIBRARY的搜索,依赖JAVA_HOME和大量预定义路径。 问题二:cmake库搜索函数find_library会搜索LD_LIBRARY_PATH吗
  通过阅读Does CMake"s find_library search LD_LIBRARY_PATH可以知道,find_library默认不搜索LD_LIBRARY_PATH, 并且网上也找不到让cmake搜索LD_LIBRARY_PATH的文章。 那cmake能搜索LD_LIBRARY_PATH吗?
  答案是可以的,通过cmake获取LD_LIBRARY_PATH环境变量,并转为cmake可理解的list格式,而后注入find_library即可,代码如下: string(REPLACE ":" ";" RUNTIME_PATH "$ENV{LD_LIBRARY_PATH}") find_library(JVM_API NAMES jvm HINTS ${RUNTIME_PATH}) if (JVM_API STREQUAL "JVM_API-NOTFOUND")  message(WARNING "found libjvm.so only in ${JAVA_JVM_LIBRARY} but not in LD_LIBRARY_PATH. environment variable LD_LIBRARY_PATH must include its" directory.") endif()
  如果希望找不到这个库时编译失败,可以将WARNING改为fatal_error, 代码如下: string(REPLACE ":" ";" RUNTIME_PATH "$ENV{LD_LIBRARY_PATH}") find_library(JVM_API NAMES jvm HINTS ${RUNTIME_PATH}) if (JVM_API STREQUAL "JVM_API-NOTFOUND")  message(FATAL_ERROR "found libjvm.so only in ${JAVA_JVM_LIBRARY} but not in LD_LIBRARY_PATH. environment variable LD_LIBRARY_PATH must include its" directory.") endif()小结
  本文通过编译后运行找不到库文件的问题引入,首先分析了find_package(JNI)的工作流程,而后针对cmake不搜索LD_LIBRARY_PATH的问题,提出了一种通用的解决办法。 参考文献:
  [1] Cmake之深入理解find_package()的用法:https://zhuanlan.zhihu.com/p/97369704?utm_source=wechat_session
  [2] Cmake中find_package命令的搜索模式之模块模式(Module mode):https://www.jianshu.com/p/f983a90bcf91
  [3]Does CMake"s find_library search LD_LIBRARY_PATH?:https://stackoverflow.com/questions/41566316/does-cmakes-find-library-search-ld-library-path
  点击下方,第一时间了解华为云新鲜技术~
  华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云

粤宏远A2022年前三季度净利润4652。50万元同比下降65。15中证智能财讯粤宏远(000573)10月29日披露2022年第三季度报告。2022年前三季度,公司实现营业总收入7。60亿元,同比下降20。80归母净利润4652。50万元,同比下最新出炉!安信中庚中泰资管主动权益规模逆势大增中国基金报记者若晖随着基金三季报全部披露完毕,基金公司的最新规模情况也新鲜出炉。今年A股市场遭遇寒冬,各大主流指数悉数回调,拖累权益基金业绩表现,固收类资产暂时成为资金的避风港。在姻缘测试你会通过相亲而脱单吗?老规矩,先让自己的心平静下来,默念ta的名字,凭第一直觉选择一张你最有感觉的牌。记得让你的闺蜜和朋友也一起来测一下哦nice文niceA恋人这张牌的出现,说明你内心非常渴望一段好的东京涩谷两天内人满为患多人当街大打出手酒后倒地睡觉东京涩谷骚乱不断(朝日电视台)海外网10月31日电据日本朝日电视台10月31日消息,东京涩谷附近地区近日举行万圣节相关活动。29日30日两天,大批民众身着奇装异服聚集在涩谷,不少人嘱托在心中蛇医生涯27载坚守基层医疗事业编者按一名党员,一面旗帜。只要每一名党员发挥先锋模范作用,多一份信仰多一份付出多一份奉献,团结广大人民群众同向同行,就能凝聚起实现中华民族伟大复兴的磅礴伟力。正值郴州市全市上下学习每日摘抄直面生活的烦恼,永远保持积极向上的力量1。新时代画卷锦绣壮丽,新征程篇章气势恢宏。2。努力完善过程,不过分看重结果。3。只要肯奋斗,未来一定充满希望。4。唯有努力向下扎根,才能不断向上生长。5。既然坚持,就要全力以赴。福建日增本土感染人数连续3天超百例首划2个高风险区中新网福州10月29日电福建省卫生健康委员会29日通报,10月28日0至24时,福建省报告新增本土确诊病例10例(厦门市1例,泉州市2例,南平市7例其中无症状感染者转确诊6例)。新信捷电气2022年前三季度净利润1。83亿元同比下降20。51中证智能财讯信捷电气(603416)10月28日披露2022年第三季度报告。2022年前三季度,公司实现营业总收入10。05亿元,同比增长3。64归母净利润1。83亿元,同比下降2浦发银行前三季度净利润454。64亿元不良率持续双降10月28日,浦发银行发布2022年三季报。前三季度,浦发银行紧抓资产高质量投放,持续推动负债增规模降成本,打造特色业务矩阵,不断增强数字赋能驱动力。前三季度浦发银行实现营业收入110月27日,关于痛苦5点起床读书。10月27日,关于痛苦。悉达多中有一句话生命即是苦痛。想起之前看圆桌派时候的一段话人死后都会去天堂,所有人都去天堂,因为这里(人间)就是地狱。想想也是,生而为人,我们其实,你再也不会回来了郝有花(图片来自网络)别过,才知一切皆是虚无你一定很想知道,在我的诗里你有多么重要其实,一切只不过是一场游戏而已假的真不了,真的假不了真真假假,假假真真一段情殇,一个句号来年,那不
蛇!很多人害怕吧山峒里多蛇,贩蛇便成了一种不错的行业,其中最有名的蛇贩子是端妹子。照当地俗称习惯,端妹子其实是男性。他额角有一大块黑皮,所以又有人叫他黑皮。黑皮原来是吃铜锣饭的,唱乔仔戏,打电视普真实的铁道游击队大队长31岁英年早逝,政委88年授中将现在抗日剧层出不穷,看得让人眼花缭乱。尤其是一些神剧,虽让人直呼过瘾,但过于偏离真实,很多人看过就忘了,不够深入人心。而有一部剧想必大家印象很深刻,它陪伴了一代又一代人,那就是铁道陈时中豪迈地踏着近万具尸体参选台湾流行疫情指挥中心30日公布,新增31488例新冠肺炎确诊病例,截至目前,累计5273449例确诊新型冠状病毒肺炎,累计9920例死亡。陈水扁在受访时批评代表民进党参选台北的陈时九合一选举民众党冲劲足!柯文哲公鸡率小鸡迎母鸡力挺县市长参选人来源台海网柯文哲将率民众党台北市议员参选人合体台北市长参选人黄珊珊(中评社图)台海网8月31日讯(海峡导报记者林连金)8月29日起,台湾年底九合一选举开始进行参选登记,各政党县市长校园枪声击碎美人权卫士假面美国全国广播公司报道称,2021至2022学年,是美国20年来校园枪支暴力最严重的一个学年。校园本应是充满琅琅书声和欢快笑声的净土。但在美国,刺耳的枪声打破了校园的安宁。据美国密歇何溢诚快评美日嘴上都是主义,心里全是生意果不其然,华航还是不顶住蔡当局压力,昨天召开临时董事会,闪电通过照单全收美国强迫推销168波音787客机,预计花费新台币1400亿元,这分明是赤裸裸的国际关说结果,官商勾结权钱交易最新通报教师李某某,开除日前,教育部公开曝光第十批7起违反教师职业行为十项准则典型案例。教育部有关负责人指出,7起典型案例涉事教师均已受到严肃处理,反映出各地各校在深入贯彻落实教师职业行为十项准则要求加强稻盛和夫的一生苦难才是真正的财富8月30日,据共同社报道,日本著名实业家稻盛和夫去世,享年90岁。稻盛和夫1932年出生于鹿儿岛。1959年,27岁的他创立了京瓷。十年后,京瓷成为世界500强企业之一。1989年今天全世界都在看的新闻2022。8。31第七届一带一路高峰论坛8月31日在香港开幕第七届一带一路高峰论坛8月31日在香港开幕,全球多名政商领袖以在线或线下方式参与论坛。香港特区行政长官李家超致开幕辞时表示,香港在项目融资伊拉克首都爆发冲突致12人死亡图说巴格达,2022年8月30日来源新华社8月29日,在伊拉克首都巴格达,救护车驶入绿区。伊拉克一名内政部官员29日说,当天在伊首都巴格达绿区举行的抗议活动中出现流血冲突,造成至少十一世班禅90后活佛,寻访人员在5000米外雪上湖泊中找到了ampampquot他ampampquot1996年3月9日,在北京市西黄寺,所有的僧人都站在寺庙的大门口等待着。这一天,西黄寺没有接待任何的香客和游客,所有人一起把寺庙打扫得干干净净的,只为等待一个贵客的到来。在众多的僧