当前位置: 首页 > news >正文

网站开发外包费用会计科目上海市建设注册管理网站

网站开发外包费用会计科目,上海市建设注册管理网站,做化妆品网站的原因,电脑网站开发者模式本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。 文章目录 正文样例代码 正文 Bazel项目引用仅使用Cmake依赖项目,目前业界最为普遍…

在这里插入图片描述本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。

文章目录

  • 正文
  • 样例代码

正文

Bazel项目引用仅使用Cmake依赖项目,目前业界最为普遍的集成方法是:将依赖项目中需要的全部文件打包成一个Bazel中的Target

原生支持Bazel的项目一般会使用细粒度的Target划分项目,就像Cmake中在不同的模块使用add_librarytarget_include_directories打包成.a,最后在生成可执行程序时一并链接,一来可以增加测试代码的编译速度,二来项目划分也更为清晰。

Bazel Cpp集成一个复杂项目时一般存在很多麻烦,包括不限于:

  1. 符号冲突
  2. 多个编译单元编译选项不同导致实例化不同,链接失败
  3. 编译选项确实或错误
  4. 繁杂的库依赖,包括依赖的依赖
  5. 特殊版本库依赖

所以如果把所有的代码集成到一个Target同时编译,开始报错会非常多,而且因为多线程编译,每次的报错还不太一样。很自然的思路就是:是否可以逐模块引入依赖项目?

来想下一般Cmake的编译流程:

  1. 各个模块所有的文件执行预处理,编译,汇编,生成多个.o文件,每一个cpp是一个编译单元
  2. ar将一个模块的文件打包为一个静态库,此时还没有链接,每个.a中符号调用还没有分配偏移地址
  3. 生成可执行文件,链接基础依赖库和之前生成的所有静态库

Bazel的原理和上述流程基本一致,但是有一个更强的保证,即多个Target之间不允许循环依赖。

这有助于让代码的结构更为清晰,但是对于细粒度的集成依赖来说是一切灾难的开始。

举个简单的例子:

// A.cpp
#include "A.h"int main()
{return 0;
}// A.h
#include "B.h"// B.cpp
#include "A.h"// B.h
#include "xxxxxx"

这种情况下Cmake是不存在循环依赖的,因为不存在头文件的互相依赖,B.oA.o在链接阶段会互相找到符号的定义。但是在Bazel中就不一样了,因为Target 必须包含对方的定义,也就成了:

// BUILD.a
cc_library(name = "A",srcs = [ "A.h", "A.cpp" ],includes = ["lib"],deps = ["//xxx:B",],
)// BUILD.b
cc_library(name = "B",srcs = [ "B.h", "B.cpp" ],includes = ["lib"],deps = ["//xxx:A",],
)

还没有进入链接阶段,在Bazel的准备阶段就已经报错循环引用了。这种情况就只能把AB包含为一个Target

如何判断Bazel集成仅使用Cmake的依赖项是否可以细粒度拆分呢?步骤其实很清晰,即:

  1. 把编译的过程看做一个有向图
  2. 每个cpp文件是一个节点
  3. cpp文件包含的.hcpp文件对应的.h包含的所有.h为有向边

这种情况下判断是否存在环。

此时对上一轮发现的环执行缩点,忽略不是环的节点,但是保留缩点后的和其他缩点节点的边,如果还存在环就要继续缩点,直到不存在环。最差的结果是最后只有一个点。

缩点的原始节点就是在bazel中必须包含在一个Target的文件。

其实一般顶级开源项目的模块划分都很清晰,一般不会出现多个模块之间大规模的互相引用,但是出现后这种判断Cmake项目是否可以逐模块拆分为Bazel的方法非常有效。

但是有一个问题,执行完这个分析后得出的不存在环的结论文件级别的,这个时候最差的情况是需要大规模的逐文件去写bazel中对应Target,虽然看起来这个流程是可以自动化的,但是确实没有精力去研究这个了。

这里就有两个劣势:

  1. 逐文件写Target过于复杂,有些本末倒置,越复杂的项目Target写的越复杂,而且极难修改
  2. 如果要升级依赖的项目,对应项目存在大规模路径变动,上面的步骤就要再来一次了

所以综上所属,“Bazel集成仅使用Cmake的依赖项目” 的通用方法就是:

  1. 把所有的文件打包成一个Target
  2. 复杂依赖项目的集成需要对代码结构有所了解,最小化引入

样例代码

这里是一个上面提到的缩点的代码实现,原则上可以判断全部cpp项目的依赖关系,判断是否可以 “轻松” 的拆分为BazelTarget

import os
import re
from collections import defaultdictEXCLUDED_DIRS = {'tests', 'test', 'benchmarks', 'fuzzer', 'docs', 'examples', 'tool', "experimental"}def find_cpp_files(directory):"""Find all .cpp files in the given directory, excluding certain subdirectories."""cpp_files = []for root, dirs, files in os.walk(directory):dirs[:] = [d for d in dirs if d not in EXCLUDED_DIRS]for file in files:if file.endswith('.cpp'):cpp_files.append(os.path.join(root, file))return cpp_filesdef extract_includes(cpp_file):"""Extract included header files from a .cpp file."""includes = []with open(cpp_file, 'r') as f:for line in f:match = re.match(r'^\s*#\s*include\s+"([^"]+)"', line)if match:includes.append(match.group(1))return includesdef build_dependency_map(cpp_files):"""Build a map of cpp files to their header file dependencies, including .h files."""dependency_map = {}for cpp_file in cpp_files:includes = extract_includes(cpp_file)relative_path = os.path.relpath(cpp_file, "/data1/exercise/velox/")base_name = os.path.splitext(relative_path)[0]dependencies = [os.path.splitext(include)[0]for include in includes if os.path.splitext(include)[0] != base_name]if base_name == 'velox/type/Tokenizer':print("===============", dependencies)h_file_path = os.path.splitext(cpp_file)[0] + '.h'if os.path.exists(h_file_path):h_includes = extract_includes(h_file_path)dependencies.extend([os.path.splitext(include)[0] for include in h_includesif os.path.splitext(include)[0] != base_name])if base_name == 'velox/type/Tokenizer':print("===============", dependencies)dependency_map[base_name] = list(set(dependencies))  return dependency_mapdef find_cycles(dependency_map):"""Detect cycles in the dependency map and return all cycle paths."""visited = set()stack = set()cycles = []def dfs(node, path):if node in stack:cycle_start_index = path.index(node)cycles.append(path[cycle_start_index:] + [node])return Trueif node in visited:return Falsevisited.add(node)stack.add(node)path.append(node)for neighbor in dependency_map.get(node, []):dfs(neighbor, path)stack.remove(node)path.pop()return Falsefor node in dependency_map:if node not in visited:dfs(node, [])return cycles# 此时只需要关心缩点后的超级点,因为其他点已经确定不存在循环依赖
def build_scc_graph(cycles, dependency_map):"""Build a new graph with strongly connected components (SCCs)."""scc_map = {}scc_to_nodes_map = defaultdict(list)for i, cycle in enumerate(cycles):for node in cycle:scc_map[node] = f"SCC_{i}" scc_to_nodes_map[f"SCC_{i}"].append(node)#print(f"    Node {node} added to SCC_{i}")scc_graph = defaultdict(set)for node, scc in scc_map.items():for neighbor in dependency_map.get(node, []):if neighbor in scc_map and scc_map[neighbor] != scc:scc_graph[scc].add(scc_map[neighbor])print("\nSCC to Node List Mapping:")for scc, nodes in scc_to_nodes_map.items():print(f"{scc}: {nodes}")return scc_graph, scc_mapdef detect_cycles_in_scc_graph(scc_graph):"""Detect cycles in the SCC graph and return cycles with their corresponding SCCs."""visited = set()stack = set()cycles = []def dfs(node, path):if node in stack:cycle_start_index = path.index(node)cycles.append(path[cycle_start_index:] + [node]) return Trueif node in visited:return Falsevisited.add(node)stack.add(node)path.append(node)for neighbor in scc_graph.get(node, []):dfs(neighbor, path)stack.remove(node)path.pop()return Falsefor node in scc_graph:if node not in visited:dfs(node, [])return cycles def main(directory):cpp_files = find_cpp_files(directory)dependency_map = build_dependency_map(cpp_files)cycles = find_cycles(dependency_map)if cycles:print("发现循环依赖:")# for cycle in cycles:#     print(" -> ".join(cycle))scc_graph, scc_map = build_scc_graph(cycles, dependency_map)scc_cycles = detect_cycles_in_scc_graph(scc_graph)if scc_cycles:print("缩点后的图中存在循环依赖:")for cycle in scc_cycles:print(" -> ".join(cycle))scc_nodes = [node for node in cycle if node in scc_map]print(f"SCC {cycle}: 包含节点 {scc_nodes}")else:print("缩点后的图中不存在循环依赖。")else:print("系统中不存在循环依赖。")if __name__ == "__main__":directory_to_check = "/data1/exercise/xxxxxxxx"main(directory_to_check)

参考:

  1. GNU GCC使用ld链接器进行链接的完整过程是怎样的?
  2. c++基础-头文件相互引用与循环依赖问题
http://www.yayakq.cn/news/423982/

相关文章:

  • 中国建设银行网站是什么好的龙岗网站建设
  • 实时开奖走势网站建设女生适合学计算机的哪个专业
  • 腾讯网站开发wordpress首页调用页面文章的内容
  • 宣传网站怎么做顺德网站建设价格
  • 有做装修效果图赚钱的网站吗厦门翔安建设局网站
  • 常州住房和城乡建设部网站google外贸建站
  • 单页营销型网站建设游戏代理300元一天
  • 游戏网站建设公司长沙做网站seo公司
  • 网站建设流《网页设计与网站建设》
  • 安徽禹尧工程建设有限公司网站wordpress 网站地图类
  • 百度网站的域名地址网站制作的软件有哪些
  • 山东建设执业师专业官方网站建设银行积分兑换商城网站
  • 杭州网站优化服务视频广告网站
  • 重庆网站建设找承越如何做百度网站推广
  • seo网站优化方案书传媒网站建设价格
  • unity做网站国外优秀摄影网站
  • 手机端网站开发多少钱浏览器网址入口
  • 代做网站的好处wordpress删除底部
  • 网站做两个版本简约风格网站建设
  • 网站建设psd辽宁省建筑工程造价信息网
  • 为什么做网站ppt定制化网站开发
  • 建站代理赚钱吗应届生去外包公司
  • 合众商道网站开发黄冈公司网站建设平台
  • 网站建设技术服务税种分类成都logo设计公司
  • 烟台住房和城乡建设厅网站做的网站显示不了背景图片
  • 灰色系网站网站建设属于无形资产吗
  • wap网站模板下载深圳为华网络科技有限公司
  • 网站建设常用编程语言园林景观设计公司质量环境职业健康安全管控
  • 网站怎么做长尾词网站文章不显示
  • 杭州做卖房子的工作哪个网站好wordpress 表格处理